Merge remote-tracking branch 'jmchilton/dev' into csv_fix

This commit is contained in:
John Chilton
2016-03-01 07:32:44 +00:00
1269 changed files with 36137 additions and 29809 deletions
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
set -e
MAX_LINE_COUNT=19900
project_dir=`dirname $0`/..
cd $project_dir
bash -c "[ `find lib/galaxy/webapps/galaxy/controllers/ -name '*.py' | xargs wc -l | tail -n 1 | awk '{ printf \$1; }'` -lt $MAX_LINE_COUNT ]"
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
set -e
MAX_MAKO_COUNT=330
project_dir=`dirname $0`/..
cd $project_dir
bash -c "[ `find templates -iname '*.mako' | wc -l | cut -f1 -d' '` -lt $MAX_MAKO_COUNT ]"
+6
View File
@@ -0,0 +1,6 @@
echo "Testing for correct startup:"
bash run.sh --daemon && sleep 30s && curl -I localhost:8080
EXIT_CODE=$?
echo "exit code:$EXIT_CODE, showing startup log:"
cat paster.log
exit $EXIT_CODE
-21
View File
@@ -4,24 +4,3 @@ database/
doc/patch.py
doc/source/conf.py
lib/galaxy/util/jstree.py
scripts/api/
scripts/data_libraries/
scripts/loc_files/
scripts/microbes/
scripts/others/
scripts/scramble/
scripts/tool_shed/
scripts/tools/
scripts/transfer.py
tools/data_source/
tools/filters/
tools/genomespace/
tools/meme/
tools/metag_tools/
tools/phenotype_association/
tools/plotting/
tools/solid_tools/
tools/sr_assembly/
tools/sr_mapping/
tools/validation/
tools/visualization/
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
set -e
flake8 --exclude `paste -sd, .ci/flake8_blacklist.txt` `paste -s .ci/py3_sources.txt`
+17
View File
@@ -0,0 +1,17 @@
lib/galaxy/util/
lib/galaxy/jobs/runners/util/
lib/pulsar/
lib/galaxy/tools/parser/
lib/galaxy/tools/lint.py
lib/galaxy/tools/lint_util.py
lib/galaxy/tools/loader.py
lib/galaxy/tools/loader_directory.py
lib/galaxy/tools/linters/
lib/galaxy/tools/deps/
lib/galaxy/tools/toolbox/
lib/galaxy/tools/parser/
lib/galaxy/jobs/metrics/
lib/galaxy/objectstore/
scripts/api/common.py
scripts/api/display.py
scripts/api/workflow_execute_parameters.py
+5 -2
View File
@@ -43,6 +43,7 @@ reports_webapp.pid
# Config files
universe_wsgi.ini
reports_wsgi.ini
reports.ini
tool_shed_wsgi.ini
# Config files.
@@ -85,12 +86,13 @@ tool-data/genome/*
tool-data/*.sample
tool-data/testtoolshed.g2.bx.psu.edu/
tool-data/toolshed.g2.bx.psu.edu/
tool-data/**/*.fa
# Test output
test-data-cache
run_framework_tests.html
run_functional_tests.html
run_toolshed_tests.html
run_api_tests.html
test/tool_shed/tmp/*
.coverage
@@ -111,7 +113,8 @@ tool-data/shared/jars/
# CSS build artifacts.
sprite-*.less
# Local node_modules and bower_components directories
# JS, Local node_modules, and bower_components directories
static/scripts/bundled
node_modules
bower_components
+18 -2
View File
@@ -1,15 +1,31 @@
language: python
python: 2.7
os:
- linux
env:
- TOX_ENV=py34-lint
- TOX_ENV=py27-lint
- TOX_ENV=py26-lint
- TOX_ENV=py27-unit
- TOX_ENV=py26-unit
- TOX_ENV=qunit
- TOX_ENV=first_startup
matrix:
include:
- os: osx
env: TOX_ENV=first_startup
language: generic
- os: osx
env: TOX_ENV=py27-unit
language: generic
before_install:
- if [ `uname` == "Darwin" ]; then bash -c "brew update && brew install python"; fi
install:
- pip install tox
- if [ "$TOX_ENV" == "qunit" ]; then bash -c 'cd test/qunit && npm install'; fi
- if [ "$TOX_ENV" == "first_startup" ]; then bash -c "bash scripts/common_startup.sh && wget -q https://github.com/jmchilton/galaxy-downloads/raw/master/db_gx_rev_0127.sqlite && mv db_gx_rev_0127.sqlite database/universe.sqlite && bash manage_db.sh -c ./config/galaxy.ini.sample upgrade"; fi
script: tox -e $TOX_ENV
notifications:
email: false
+121
View File
@@ -0,0 +1,121 @@
RELEASE_CURR:=16.01
RELEASE_CURR_MINOR_NEXT:=$(shell expr `awk '$$1 == "VERSION_MINOR" {print $$NF}' lib/galaxy/version.py | tr -d \" | sed 's/None/0/' ` + 1)
RELEASE_NEXT:=16.04
# TODO: This needs to be updated with create_release_rc
#RELEASE_NEXT_BRANCH:=release_$(RELEASE_NEXT)
RELEASE_NEXT_BRANCH:=dev
RELEASE_UPSTREAM:=upstream
GRUNT_DOCKER_NAME:=galaxy/client-builder:16.01
all:
@echo "This makefile is primarily used for building Galaxy's JS client. A sensible all target is not yet implemented."
npm-deps:
cd client && npm install
grunt: npm-deps
cd client && node_modules/grunt-cli/bin/grunt
style: npm-deps
cd client && node_modules/grunt-cli/bin/grunt style
webpack: npm-deps
cd client && node_modules/webpack/bin/webpack.js -p
client: grunt style webpack
grunt-docker-image:
docker build -t ${GRUNT_DOCKER_NAME} client
grunt-docker: grunt-docker-image
docker run -it -v `pwd`:/data ${GRUNT_DOCKER_NAME}
clean-grunt-docker-image:
docker rmi ${GRUNT_DOCKER_NAME}
# Release Targets
create_release_rc:
git checkout dev
git pull --ff-only ${RELEASE_UPSTREAM} dev
git push origin dev
git checkout -b release_$(RELEASE_CURR)
git push origin release_$(RELEASE_CURR)
git push ${RELEASE_UPSTREAM} release_$(RELEASE_CURR)
git checkout -b version-$(RELEASE_CURR)
sed -i "s/^VERSION_MAJOR = .*/VERSION_MAJOR = \"$(RELEASE_CURR)\"/" lib/galaxy/version.py
sed -i "s/^VERSION_MINOR = .*/VERSION_MINOR = \"rc1\"/" lib/galaxy/version.py
git add lib/galaxy/version.py
git commit -m "Update version to $(RELEASE_CURR).rc1"
git checkout dev
git checkout -b version-$(RELEASE_NEXT).dev
sed -i "s/^VERSION_MAJOR = .*/VERSION_MAJOR = \"$(RELEASE_NEXT)\"/" lib/galaxy/version.py
git add lib/galaxy/version.py
git commit -m "Update version to $(RELEASE_NEXT).dev"
-git merge version-$(RELEASE_CURR)
git checkout --ours lib/galaxy/version.py
git add lib/galaxy/version.py
git commit -m "Merge branch 'version-$(RELEASE_CURR)' into version-$(RELEASE_NEXT).dev"
git push origin version-$(RELEASE_CURR):version-$(RELEASE_CURR)
git push origin version-$(RELEASE_NEXT).dev:version-$(RELEASE_NEXT).dev
git branch -d version-$(RELEASE_CURR)
git branch -d version-$(RELEASE_NEXT).dev
create_release:
git pull --ff-only $(RELEASE_UPSTREAM) master
git push origin master
git checkout release_$(RELEASE_CURR)
git pull --ff-only $(RELEASE_UPSTREAM) release_$(RELEASE_CURR)
#git push origin release_$(RELEASE_CURR)
git checkout dev
git pull --ff-only $(RELEASE_UPSTREAM) dev
#git push origin dev
# Test run of merging. If there are conflicts, it will fail here here.
git merge release_$(RELEASE_CURR)
git checkout release_$(RELEASE_CURR)
sed -i "s/^VERSION_MINOR = .*/VERSION_MINOR = None/" lib/galaxy/version.py
git add lib/galaxy/version.py
git commit -m "Update version to $(RELEASE_CURR)"
git tag -m "Tag version $(RELEASE_CURR)" v$(RELEASE_CURR)
git checkout dev
-git merge release_$(RELEASE_CURR)
git checkout --ours lib/galaxy/version.py
git add lib/galaxy/version.py
git commit -m "Merge branch 'release_$(RELEASE_CURR)' into dev"
git checkout master
git merge release_$(RELEASE_CURR)
#git push origin release_$(RELEASE_CURR):release_$(RELEASE_CURR)
#git push origin dev:dev
#git push origin master:master
#git push origin --tags
create_point_release:
git pull --ff-only $(RELEASE_UPSTREAM) master
git push origin master
git checkout release_$(RELEASE_CURR)
git pull --ff-only $(RELEASE_UPSTREAM) release_$(RELEASE_CURR)
#git push origin release_$(RELEASE_CURR)
git checkout $(RELEASE_NEXT_BRANCH)
git pull --ff-only $(RELEASE_UPSTREAM) $(RELEASE_NEXT_BRANCH)
#git push origin $(RELEASE_NEXT_BRANCH)
git merge release_$(RELEASE_CURR)
git checkout release_$(RELEASE_CURR)
sed -i "s/^VERSION_MINOR = .*/VERSION_MINOR = \"$(RELEASE_CURR_MINOR_NEXT)\"/" lib/galaxy/version.py
git add lib/galaxy/version.py
git commit -m "Update version to $(RELEASE_CURR).$(RELEASE_CURR_MINOR_NEXT)"
git tag -m "Tag version $(RELEASE_CURR).$(RELEASE_CURR_MINOR_NEXT)" v$(RELEASE_CURR).$(RELEASE_CURR_MINOR_NEXT)
git checkout $(RELEASE_NEXT_BRANCH)
-git merge release_$(RELEASE_CURR)
git checkout --ours lib/galaxy/version.py
git add lib/galaxy/version.py
git commit -m "Merge branch 'release_$(RELEASE_CURR)' into $(RELEASE_NEXT_BRANCH)"
git checkout master
git merge release_$(RELEASE_CURR)
#git push origin release_$(RELEASE_CURR):release_$(RELEASE_CURR)
#git push origin $(RELEASE_NEXT_BRANCH):release_$(RELEASE_NEXT_BRANCH)
#git push origin master:master
#git push origin --tags
git checkout release_$(RELEASE_CURR)
+3 -3
View File
@@ -11,9 +11,9 @@ The latest information about Galaxy is available via `https://galaxyproject.org/
:target: https://webchat.freenode.net/?channels=galaxyproject
:alt: Chat with us
.. image:: https://readthedocs.org/projects/galaxy/badge/?version=master
:target: https://galaxy.readthedocs.org/en/master/
:alt: Documentation Status
.. image:: https://img.shields.io/badge/docs-release-green.svg
:target: https://docs.galaxyproject.org/en/master/
:alt: Release Documentation
.. image:: https://travis-ci.org/galaxyproject/galaxy.svg?branch=dev
:target: https://travis-ci.org/galaxyproject/galaxy
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
cd /data/client && \
npm install && \
grunt
+13
View File
@@ -0,0 +1,13 @@
FROM digitallyseamless/nodejs-bower-grunt
RUN mkdir /gx
COPY package.json /gx/package.json
RUN cd /gx && \
npm install -g && \
cd / && \
rm -rf /gx
WORKDIR /data/client
ADD ./.docker-build.sh /build.sh
CMD ["/build.sh"]
+1 -1
View File
@@ -24,5 +24,5 @@ module.exports = function(grunt) {
// see the sub directory grunt-tasks/ for individual task definitions
grunt.loadTasks( 'grunt-tasks' );
// note: 'handlebars' *not* 'templates' since handlebars doesn't call uglify
grunt.registerTask( 'default', [ 'check-modules', 'handlebars', 'uglify' ] );
grunt.registerTask( 'default', [ 'check-modules', 'uglify', 'webpack' ] );
};
+38 -11
View File
@@ -4,9 +4,24 @@ Client Build System
Builds and moves the client-side scripts necessary for running the Galaxy webapps. There's no need to use this system
unless you are modifying or developing client-side scripts.
You'll need Node and the Node Package Manager (npm): nodejs.org.
The base dependencies you'll need are Node.js and the Node Package Manager
(npm). See nodejs.org for more information.
Once npm is installed, install the grunt task manager and it's command line into your global scope:
Simple Full Build
=================
The simplest way to rebuild the entire client to incorporate any local changes
is to run the 'client' rule in the Galaxy makefile, which is in the repository
root. This will also ensure any local node modules are installed.
make client
Detailed Build Instructions
===========================
Once npm is installed, install the grunt task manager and its command line into your global scope:
npm install -g grunt grunt-cli
@@ -31,26 +46,38 @@ This will:
1. compress the files in client/galaxy/scripts and place them in static/scripts
2. generate source maps and place them in static/maps
3. rebuild the webpack-based client apps
Templates
=========
Rebuilding Scripts Only
=======================
You can change and recompile the templates by using:
To re-minify all the individual javascript files:
grunt templates
grunt scripts
This will:
1. recompile the templates in client/galaxy/scripts/templates to client/galaxy/scripts/templates/compiled
2. minify and generate source maps for the compiled templates
Rebuilding Webpack Apps
=======================
To rebuild the webpack bundles for apps (compressed for production):
grunt webpack
To rebuild the apps without compression:
grunt webpack-dev
To rebuild without compression and watch and rebuild when scripts change:
grunt webpack-watch
Changing Styles/CSS
===================
The CSS and styling used by Galaxy is also controlled from this directory. Galaxy uses LESS, a superset of CSS that
compiles to CSS, for its styling. LESS files are kept in client/galaxy/style/less. Compiled CSS is in statis/style/blue.
compiles to CSS, for its styling. LESS files are kept in client/galaxy/style/less. Compiled CSS is in static/style/blue.
Use grunt to recompile the LESS in into CSS (from the `client` directory):
@@ -91,4 +118,4 @@ The commands mentioned above in 'Rebuilding' and 'Grunt watch' also can be appli
`--app=toolshed` option:
grunt watch --app=toolshed
grunt --app=toolshed
grunt --app=toolshed
+1 -1
View File
@@ -14,6 +14,7 @@
"underscore": "~1.7.0",
"backbone": "~1.1.2",
"bootstrap": "~3.3.2",
"bootstrap-tour": "~0.10.2",
"d3": "~3.5.3",
"farbtastic": "~2.0.0-alpha.1",
"toastr": "~2.1.0",
@@ -30,7 +31,6 @@
"jstree": "~3.0.9",
"jquery-ui": "git://github.com/jquery/jquery-ui.git#~1.11.2",
"threedubmedia.jquery.event": "*",
"handlebars": "~3.0.0",
"jquery-migrate": "~1.2.1",
"requirejs": "~2.1.17"
},
+175
View File
@@ -0,0 +1,175 @@
var jQuery = require( 'jquery' ),
$ = jQuery,
GalaxyApp = require( 'galaxy' ).GalaxyApp,
QUERY_STRING = require( 'utils/query-string-parsing' ),
PANEL = require( 'layout/panel' ),
ToolPanel = require( './tool-panel' ),
HistoryPanel = require( './history-panel' ),
PAGE = require( 'layout/page' ),
ToolForm = require( 'mvc/tool/tool-form' ),
Tours = require( 'mvc/tours' );
/** define the 'Analyze Data'/analysis/main/home page for Galaxy
* * has a masthead
* * a left tool menu to allow the user to load tools in the center panel
* * a right history menu that shows the user's current data
* * a center panel
* Both panels (generally) persist while the center panel shows any
* UI needed for the current step of an analysis, like:
* * tool forms to set tool parameters,
* * tables showing the contents of datasets
* * etc.
*/
window.app = function app( options, bootstrapped ){
window.Galaxy = new GalaxyApp( options, bootstrapped );
Galaxy.debug( 'analysis app' );
// TODO: use router as App base (combining with Galaxy)
// .................................................... panels and page
var config = options.config,
toolPanel = new ToolPanel({
el : '#left',
userIsAnonymous : Galaxy.user.isAnonymous(),
search_url : config.search_url,
toolbox : config.toolbox,
toolbox_in_panel : config.toolbox_in_panel,
stored_workflow_menu_entries : config.stored_workflow_menu_entries,
nginx_upload_path : config.nginx_upload_path,
ftp_upload_site : config.ftp_upload_site,
default_genome : config.default_genome,
default_extension : config.default_extension,
}),
centerPanel = new PANEL.CenterPanel({
el : '#center'
}),
historyPanel = new HistoryPanel({
el : '#right',
galaxyRoot : Galaxy.root,
userIsAnonymous : Galaxy.user.isAnonymous(),
allow_user_dataset_purge: config.allow_user_dataset_purge,
}),
analysisPage = new PAGE.PageLayoutView( _.extend( options, {
el : 'body',
left : toolPanel,
center : centerPanel,
right : historyPanel,
}));
// .................................................... decorate the galaxy object
// TODO: most of this is becoming unnecessary as we move to apps
Galaxy.page = analysisPage;
Galaxy.params = Galaxy.config.params;
// add tool panel to Galaxy object
Galaxy.toolPanel = toolPanel.tool_panel;
Galaxy.upload = toolPanel.uploadButton;
Galaxy.currHistoryPanel = historyPanel.historyView;
Galaxy.currHistoryPanel.listenToGalaxy( Galaxy );
//HACK: move there
Galaxy.app = {
display : function( view, target ){
// TODO: Remove this line after select2 update
$( '.select2-hidden-accessible' ).remove();
centerPanel.display( view );
},
};
// .................................................... routes
/** */
var router = new ( Backbone.Router.extend({
// TODO: not many client routes at this point - fill and remove from server.
// since we're at root here, this may be the last to be routed entirely on the client.
initialize : function( options ){
this.options = options;
},
/** override to parse query string into obj and send to each route */
execute: function( callback, args, name ){
Galaxy.debug( 'router execute:', callback, args, name );
var queryObj = QUERY_STRING.parse( args.pop() );
args.push( queryObj );
if( callback ){
callback.apply( this, args );
}
},
routes : {
'(/)' : 'home',
// TODO: remove annoying 'root' from root urls
'(/)root*' : 'home',
'(/)tours(/:tour_id)' : 'show_tours',
},
show_tours : function( tour_id ){
if (tour_id){
Tours.giveTour(tour_id);
}
else{
centerPanel.display( new Tours.ToursView() );
}
},
/** */
home : function( params ){
// TODO: to router, remove Globals
// load a tool by id (tool_id) or rerun a previous tool execution (job_id)
if( ( params.tool_id || params.job_id ) && params.tool_id !== 'upload1' ){
this._loadToolForm( params );
} else {
// show the workflow run form
if( params.workflow_id ){
this._loadCenterIframe( 'workflow/run?id=' + params.workflow_id );
// load the center iframe with controller.action: galaxy.org/?m_c=history&m_a=list -> history/list
} else if( params.m_c ){
this._loadCenterIframe( params.m_c + '/' + params.m_a );
// show the workflow run form
} else {
this._loadCenterIframe( 'welcome' );
}
}
},
/** load the center panel with a tool form described by the given params obj */
_loadToolForm : function( params ){
//TODO: load tool form code async
params.id = params.tool_id;
centerPanel.display( new ToolForm.View( params ) );
},
/** load the center panel iframe using the given url */
_loadCenterIframe : function( url, root ){
root = root || Galaxy.root;
url = root + url;
centerPanel.$( '#galaxy_main' ).prop( 'src', url );
},
}))( options );
// .................................................... when the page is ready
// render and start the router
$(function(){
analysisPage
.render()
.right.historyView.loadCurrentHistory();
// use galaxy to listen to history size changes and then re-fetch the user's total size (to update the quota meter)
// TODO: we have to do this here (and after every page.render()) because the masthead is re-created on each
// page render. It's re-created each time because there is no render function and can't be re-rendered without
// re-creating it.
Galaxy.listenTo( analysisPage.right.historyView, 'history-size-change', function(){
// fetch to update the quota meter adding 'current' for any anon-user's id
Galaxy.user.fetch({ url: Galaxy.user.urlRoot() + '/' + ( Galaxy.user.id || 'current' ) });
});
analysisPage.right.historyView.connectToQuotaMeter( analysisPage.masthead.quotaMeter );
// start the router - which will call any of the routes above
Backbone.history.start({
root : Galaxy.root,
pushState : true,
});
});
};
@@ -0,0 +1,85 @@
var RightPanel = require( 'layout/panel' ).RightPanel,
Ui = require( 'mvc/ui/ui-misc' ),
historyOptionsMenu = require( 'mvc/history/options-menu' );
CurrentHistoryView = require( 'mvc/history/history-view-edit-current' ).CurrentHistoryView,
_l = require( 'utils/localization' );
/** the right hand panel in the analysis page that shows the current history */
var HistoryPanel = RightPanel.extend({
title : _l( 'History' ),
initialize : function( options ){
RightPanel.prototype.initialize.call( this, options );
var self = this;
// this button re-fetches the history and contents and re-renders the history panel
this.refreshButton = new Ui.ButtonLink({
id : 'history-refresh-button',
title : _l( 'Refresh history' ),
cls : 'panel-header-button',
icon : 'fa fa-refresh',
onclick : function() {
self.historyView.loadCurrentHistory();
}
});
// opens a drop down menu with history related functions (like view all, delete, share, etc.)
this.optionsButton = new Ui.ButtonLink({
id : 'history-options-button',
title : _l( 'History options' ),
cls : 'panel-header-button',
icon : 'fa fa-cog',
});
// goes to a page showing all the users histories in panel form (for logged in users)
this.viewMultiButton = null;
if( !options.userIsAnonymous ){
this.viewMultiButton = new Ui.ButtonLink({
id : 'history-view-multi-button',
title : _l( 'View all histories' ),
cls : 'panel-header-button',
icon : 'fa fa-columns',
href : options.galaxyRoot + 'history/view_multiple'
});
}
// build history options menu
this.optionsMenu = historyOptionsMenu( this.optionsButton.$el, {
anonymous : options.userIsAnonymous,
purgeAllowed : options.allow_user_dataset_purge,
root : options.galaxyRoot
});
// view of the current history
this.historyView = new CurrentHistoryView({
purgeAllowed : options.allow_user_dataset_purge,
linkTarget : 'galaxy_main',
$scrollContainer: function(){ return this.$el.parent(); }
});
},
render : function(){
RightPanel.prototype.render.call( this );
this.$( '.unified-panel-header' ).addClass( 'history-panel-header' );
this.$( '.panel-header-buttons' ).append([
this.refreshButton.$el,
this.optionsButton.$el,
this.viewMultiButton? this.viewMultiButton.$el : null,
]);
this.historyView
.setElement( this.$( '.history-panel' ) );
// causes blink/flash due to loadCurrentHistory rendering as well
// .render();
},
_templateBody : function( data ){
return [
'<div class="unified-panel-body unified-panel-body-background">',
'<div id="current-history-panel" class="history-panel"/>',
'</div>'
].join('');
},
toString : function(){ return 'HistoryPanel'; }
});
module.exports = HistoryPanel;
+44
View File
@@ -0,0 +1,44 @@
var jQuery = require( 'jquery' ),
$ = jQuery,
GalaxyApp = require( 'galaxy' ).GalaxyApp,
PANEL = require( 'layout/panel' ),
_l = require( 'utils/localization' ),
PAGE = require( 'layout/page' );
window.app = function app( options, bootstrapped ){
window.Galaxy = new GalaxyApp( options, bootstrapped );
Galaxy.debug( 'login app' );
var redirect = encodeURI( options.redirect );
// TODO: remove iframe for user login (at least) and render login page from here
// then remove this redirect
if( !options.show_welcome_with_login ){
var params = jQuery.param({ use_panels : 'True', redirect : redirect });
window.location.href = Galaxy.root + 'user/login?' + params;
return;
}
var loginPage = new PAGE.PageLayoutView( _.extend( options, {
el : 'body',
center : new PANEL.CenterPanel({ el : '#center' }),
right : new PANEL.RightPanel({
title : _l( 'Login required' ),
el : '#right'
}),
}));
$(function(){
// TODO: incorporate *actual* referrer/redirect info as the original page does
var params = jQuery.param({ redirect : redirect }),
loginUrl = Galaxy.root + 'user/login?' + params;
loginPage.render();
// welcome page (probably) needs to remain sandboxed
loginPage.center.$( '#galaxy_main' ).prop( 'src', options.welcome_url );
loginPage.right.$( '.unified-panel-body' )
.css( 'overflow', 'hidden' )
.html( '<iframe src="' + loginUrl + '" frameborder="0" style="width: 100%; height: 100%;"/>' );
});
};
+115
View File
@@ -0,0 +1,115 @@
var LeftPanel = require( 'layout/panel' ).LeftPanel,
Tools = require( 'mvc/tool/tools' ),
Upload = require( 'mvc/upload/upload-view' ),
_l = require( 'utils/localization' );
/* Builds the tool menu panel on the left of the analysis page */
var ToolPanel = LeftPanel.extend({
title : _l( 'Tools' ),
initialize: function( options ){
LeftPanel.prototype.initialize.call( this, options );
this.log( this + '.initialize:', options );
/** @type {Object[]} descriptions of user's workflows to be shown in the tool menu */
this.stored_workflow_menu_entries = options.stored_workflow_menu_entries || [];
// create tool search, tool panel, and tool panel view.
var tool_search = new Tools.ToolSearch({
search_url : options.search_url,
hidden : false
});
var tools = new Tools.ToolCollection( options.toolbox );
this.tool_panel = new Tools.ToolPanel({
tool_search : tool_search,
tools : tools,
layout : options.toolbox_in_panel
});
this.tool_panel_view = new Tools.ToolPanelView({ model: this.tool_panel });
// add upload modal
this.uploadButton = new Upload({
nginx_upload_path : options.nginx_upload_path,
ftp_upload_site : options.ftp_upload_site,
default_genome : options.default_genome,
default_extension : options.default_extension,
});
},
render : function(){
var self = this;
LeftPanel.prototype.render.call( self );
self.$( '.panel-header-buttons' ).append( self.uploadButton.$el );
// if there are tools, render panel and display everything
if (self.tool_panel.get( 'layout' ).size() > 0) {
self.tool_panel_view.render();
//TODO: why the hide/show?
self.$( '.toolMenu' ).show();
}
self.$( '.toolMenuContainer' ).prepend( self.tool_panel_view.$el );
self._renderWorkflowMenu();
// if a tool link has the minsizehint attribute, handle it here (gen. by hiding the tool panel)
self.$( 'a[minsizehint]' ).click( function() {
if ( parent.handle_minwidth_hint ) {
parent.handle_minwidth_hint( $( self ).attr( 'minsizehint' ) );
}
});
},
/** build the dom for the workflow portion of the tool menu */
_renderWorkflowMenu : function(){
var self = this;
// add internal workflow list
self.$( '#internal-workflows' ).append( self._templateTool({
title : _l( 'All workflows' ),
href : 'workflow/list_for_run'
}));
_.each( self.stored_workflow_menu_entries, function( menu_entry ){
self.$( '#internal-workflows' ).append( self._templateTool({
title : menu_entry.stored_workflow.name,
href : 'workflow/run?id=' + menu_entry.encoded_stored_workflow_id
}));
});
},
/** build a link to one tool */
_templateTool: function( tool ) {
return [
'<div class="toolTitle">',
// global
'<a href="', Galaxy.root, tool.href, '" target="galaxy_main">', tool.title, '</a>',
'</div>'
].join('');
},
/** override to include inital menu dom and workflow section */
_templateBody : function(){
return [
'<div class="unified-panel-body unified-panel-body-background">',
'<div class="toolMenuContainer">',
'<div class="toolMenu" style="display: none">',
'<div id="search-no-results" style="display: none; padding-top: 5px">',
'<em><strong>', _l( 'Search did not match any tools.' ), '</strong></em>',
'</div>',
'</div>',
'<div class="toolSectionPad"/>',
'<div class="toolSectionPad"/>',
'<div class="toolSectionTitle" id="title_XXinternalXXworkflow">',
'<span>', _l( 'Workflows' ), '</span>',
'</div>',
'<div id="internal-workflows" class="toolSectionBody">',
'<div class="toolSectionBg"/>',
'</div>',
'</div>',
'</div>'
].join('');
},
toString : function(){ return 'ToolPanel'; }
});
module.exports = ToolPanel;
-15
View File
@@ -1,15 +0,0 @@
define( [], function() {
var Base = function() {
if( this.initialize ) {
this.initialize.apply(this, arguments);
}
};
Base.extend = Backbone.Model.extend;
return {
Base: Base,
Backbone: Backbone
};
});
-634
View File
@@ -1,634 +0,0 @@
// requestAnimationFrame polyfill
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelRequestAnimationFrame = window[vendors[x]+
'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
// IE doesn't implement Array.indexOf
if (!Array.indexOf) {
Array.prototype.indexOf = function(obj) {
for (var i = 0, len = this.length; i < len; i++) {
if (this[i] == obj) {
return i;
}
}
return -1;
};
}
// Returns the number of keys (elements) in an array/dictionary.
function obj_length(obj) {
if (obj.length !== undefined) {
return obj.length;
}
var count = 0;
for (var element in obj) {
count++;
}
return count;
}
$.fn.makeAbsolute = function(rebase) {
return this.each(function() {
var el = $(this);
var pos = el.position();
el.css({
position: "absolute",
marginLeft: 0, marginTop: 0,
top: pos.top, left: pos.left,
right: $(window).width() - ( pos.left + el.width() )
});
if (rebase) {
el.remove().appendTo("body");
}
});
};
/**
* Sets up popupmenu rendering and binds options functions to the appropriate links.
* initial_options is a dict with text describing the option pointing to either (a) a
* function to perform; or (b) another dict with two required keys, 'url' and 'action' (the
* function to perform. (b) is useful for exposing the underlying URL of the option.
*/
function make_popupmenu(button_element, initial_options) {
/* Use the $.data feature to store options with the link element.
This allows options to be changed at a later time
*/
var element_menu_exists = (button_element.data("menu_options"));
button_element.data("menu_options", initial_options);
// If element already has menu, nothing else to do since HTML and actions are already set.
if (element_menu_exists) { return; }
button_element.bind("click.show_popup", function(e) {
// Close existing visible menus
$(".popmenu-wrapper").remove();
// Need setTimeouts so clicks don't interfere with each other
setTimeout( function() {
// Dynamically generate the wrapper holding all the selectable options of the menu.
var menu_element = $( "<ul class='dropdown-menu' id='" + button_element.attr('id') + "-menu'></ul>" );
var options = button_element.data("menu_options");
if (obj_length(options) <= 0) {
$("<li>No Options.</li>").appendTo(menu_element);
}
$.each( options, function( k, v ) {
if (v) {
// Action can be either an anonymous function and a mapped dict.
var action = v.action || v;
menu_element.append( $("<li></li>").append( $("<a>").attr("href", v.url).html(k).click(action) ) );
} else {
menu_element.append( $("<li></li>").addClass( "head" ).append( $("<a href='#'></a>").html(k) ) );
}
});
var wrapper = $( "<div class='popmenu-wrapper' style='position: absolute;left: 0; top: -1000;'></div>" )
.append( menu_element ).appendTo( "body" );
var x = e.pageX - wrapper.width() / 2 ;
x = Math.min( x, $(document).scrollLeft() + $(window).width() - $(wrapper).width() - 5 );
x = Math.max( x, $(document).scrollLeft() + 5 );
wrapper.css({
top: e.pageY,
left: x
});
}, 10);
setTimeout( function() {
// Bind click event to current window and all frames to remove any visible menus
// Bind to document object instead of window object for IE compat
var close_popup = function(el) {
$(el).bind("click.close_popup", function() {
$(".popmenu-wrapper").remove();
el.unbind("click.close_popup");
});
};
close_popup( $(window.document) ); // Current frame
close_popup( $(window.top.document) ); // Parent frame
for (var frame_id = window.top.frames.length; frame_id--;) { // Sibling frames
var frame = $(window.top.frames[frame_id].document);
close_popup(frame);
}
}, 50);
return false;
});
}
/**
* Convert two seperate (often adjacent) divs into galaxy popupmenu
* - div 1 contains a number of anchors which become the menu options
* - div 1 should have a 'popupmenu' attribute
* - this popupmenu attribute contains the id of div 2
* - div 2 becomes the 'face' of the popupmenu
*
* NOTE: make_popup_menus finds and operates on all divs with a popupmenu attr (no need to point it at something)
* but (since that selector searches the dom on the page), you can send a parent in
* NOTE: make_popup_menus, and make_popupmenu are horrible names
*/
function make_popup_menus( parent ) {
// find all popupmenu menu divs (divs that contains anchors to be converted to menu options)
// either in the parent or the document if no parent passed
parent = parent || document;
$( parent ).find( "div[popupmenu]" ).each( function() {
var options = {};
var menu = $(this);
// find each anchor in the menu, convert them into an options map: { a.text : click_function }
menu.find( "a" ).each( function() {
var link = $(this),
link_dom = link.get(0),
confirmtext = link_dom.getAttribute( "confirm" ),
href = link_dom.getAttribute( "href" ),
target = link_dom.getAttribute( "target" );
// no href - no function (gen. a label)
if (!href) {
options[ link.text() ] = null;
} else {
options[ link.text() ] = {
url: href,
action: function( event ) {
// if theres confirm text, send the dialog
if ( !confirmtext || confirm( confirmtext ) ) {
// link.click() doesn't use target for some reason,
// so manually do it here.
if (target) {
window.open(href, target);
return false;
}
// For all other links, do the default action.
else {
link.click();
}
} else {
event.preventDefault();
}
}
};
}
});
// locate the element with the id corresponding to the menu's popupmenu attr
var box = $( parent ).find( "#" + menu.attr( 'popupmenu' ) );
// For menus with clickable link text, make clicking on the link go through instead
// of activating the popup menu
box.find("a").bind("click", function(e) {
e.stopPropagation(); // Stop bubbling so clicking on the link goes through
return true;
});
// attach the click events and menu box building to the box element
make_popupmenu(box, options);
box.addClass("popup");
menu.remove();
});
}
$.fn.refresh_select2 = function() {
var select_elt = $(this);
var options = { placeholder:'Click to select',
closeOnSelect: !select_elt.is("[MULTIPLE]"),
dropdownAutoWidth : true,
containerCssClass: 'select2-minwidth'
};
return select_elt.select2( options );
}
// Replace select box with a text input box + autocomplete.
function replace_big_select_inputs(min_length, max_length, select_elts) {
// To do replace, the select2 plugin must be loaded.
if (!jQuery.fn.select2) {
return;
}
// Set default for min_length and max_length
if (min_length === undefined) {
min_length = 20;
}
if (max_length === undefined) {
max_length = 3000;
}
select_elts = select_elts || $('select');
select_elts.each( function() {
var select_elt = $(this).not('[multiple]');
// Make sure that options is within range.
var num_options = select_elt.find('option').length;
if ( (num_options < min_length) || (num_options > max_length) ) {
return;
}
if (select_elt.hasClass("no-autocomplete")) {
return;
}
/* Replaced jQuery.autocomplete with select2, notes:
* - multiple selects are supported
* - the original element is updated with the value, convert_to_values should not be needed
* - events are fired when updating the original element, so refresh_on_change should just work
*
* - should we still sort dbkey fields here?
*/
select_elt.refresh_select2();
});
}
/**
* Make an element with text editable: (a) when user clicks on text, a textbox/area
* is provided for editing; (b) when enter key pressed, element's text is set and on_finish
* is called.
*/
// TODO: use this function to implement async_save_text (implemented below).
$.fn.make_text_editable = function(config_dict) {
// Get config options.
var num_cols = ("num_cols" in config_dict ? config_dict.num_cols : 30),
num_rows = ("num_rows" in config_dict ? config_dict.num_rows : 4),
use_textarea = ("use_textarea" in config_dict ? config_dict.use_textarea : false),
on_finish = ("on_finish" in config_dict ? config_dict.on_finish : null),
help_text = ("help_text" in config_dict ? config_dict.help_text : null);
// Add element behavior.
var container = $(this);
container.addClass("editable-text").click(function(e) {
// If there's already an input element, editing is active, so do nothing.
if ($(this).children(":input").length > 0) {
return;
}
container.removeClass("editable-text");
// Handler for setting element text.
var set_text = function(new_text) {
container.find(":input").remove();
if (new_text !== "") {
container.text(new_text);
}
else {
// No text; need a line so that there is a click target.
container.html("<br>");
}
container.addClass("editable-text");
if (on_finish) {
on_finish(new_text);
}
};
// Create input element(s) for editing.
var cur_text = ("cur_text" in config_dict ? config_dict.cur_text : container.text() ),
input_elt, button_elt;
if (use_textarea) {
input_elt = $("<textarea/>")
.attr({ rows: num_rows, cols: num_cols }).text($.trim(cur_text))
.keyup(function(e) {
if (e.keyCode === 27) {
// Escape key.
set_text(cur_text);
}
});
button_elt = $("<button/>").text("Done").click(function() {
set_text(input_elt.val());
// Return false so that click does not propogate to container.
return false;
});
}
else {
input_elt = $("<input type='text'/>").attr({ value: $.trim(cur_text), size: num_cols })
.blur(function() {
set_text(cur_text);
}).keyup(function(e) {
if (e.keyCode === 27) {
// Escape key.
$(this).trigger("blur");
} else if (e.keyCode === 13) {
// Enter key.
set_text($(this).val());
}
// Do not propogate event to avoid unwanted side effects.
e.stopPropagation();
});
}
// Replace text with input object(s) and focus & select.
container.text("");
container.append(input_elt);
if (button_elt) {
container.append(button_elt);
}
input_elt.focus();
input_elt.select();
// Do not propogate to elements below b/c that blurs input and prevents it from being used.
e.stopPropagation();
});
// Add help text if there some.
if (help_text) {
container.attr("title", help_text).tooltip();
}
return container;
};
/**
* Edit and save text asynchronously.
*/
function async_save_text( click_to_edit_elt, text_elt_id, save_url,
text_parm_name, num_cols, use_textarea, num_rows, on_start, on_finish ) {
// Set defaults if necessary.
if (num_cols === undefined) {
num_cols = 30;
}
if (num_rows === undefined) {
num_rows = 4;
}
// Set up input element.
$("#" + click_to_edit_elt).click(function() {
// Check if this is already active
if ( $("#renaming-active").length > 0) {
return;
}
var text_elt = $("#" + text_elt_id),
old_text = text_elt.text(),
t;
if (use_textarea) {
t = $("<textarea></textarea>").attr({ rows: num_rows, cols: num_cols }).text( $.trim(old_text) );
} else {
t = $("<input type='text'></input>").attr({ value: $.trim(old_text), size: num_cols });
}
t.attr("id", "renaming-active");
t.blur( function() {
$(this).remove();
text_elt.show();
if (on_finish) {
on_finish(t);
}
});
t.keyup( function( e ) {
if ( e.keyCode === 27 ) {
// Escape key
$(this).trigger( "blur" );
} else if ( e.keyCode === 13 ) {
// Enter key submits
var ajax_data = {};
ajax_data[text_parm_name] = $(this).val();
$(this).trigger( "blur" );
$.ajax({
url: save_url,
data: ajax_data,
error: function() {
alert( "Text editing for elt " + text_elt_id + " failed" );
// TODO: call finish or no? For now, let's not because error occurred.
},
success: function(processed_text) {
// Set new text and call finish method.
if (processed_text !== "") {
text_elt.text(processed_text);
} else {
text_elt.html("<em>None</em>");
}
if (on_finish) {
on_finish(t);
}
}
});
}
});
if (on_start) {
on_start(t);
}
// Replace text with input object and focus & select.
text_elt.hide();
t.insertAfter(text_elt);
t.focus();
t.select();
return;
});
}
function commatize( number ) {
number += ''; // Convert to string
var rgx = /(\d+)(\d{3})/;
while (rgx.test(number)) {
number = number.replace(rgx, '$1' + ',' + '$2');
}
return number;
}
// Reset tool search to start state.
function reset_tool_search( initValue ) {
// Function may be called in top frame or in tool_menu_frame;
// in either case, get the tool menu frame.
var tool_menu_frame = $("#galaxy_tools").contents();
if (tool_menu_frame.length === 0) {
tool_menu_frame = $(document);
}
// Remove classes that indicate searching is active.
$(this).removeClass("search_active");
tool_menu_frame.find(".toolTitle").removeClass("search_match");
// Reset visibility of tools and labels.
tool_menu_frame.find(".toolSectionBody").hide();
tool_menu_frame.find(".toolTitle").show();
tool_menu_frame.find(".toolPanelLabel").show();
tool_menu_frame.find(".toolSectionWrapper").each( function() {
if ($(this).attr('id') !== 'recently_used_wrapper') {
// Default action.
$(this).show();
} else if ($(this).hasClass("user_pref_visible")) {
$(this).show();
}
});
tool_menu_frame.find("#search-no-results").hide();
// Reset search input.
tool_menu_frame.find("#search-spinner").hide();
if (initValue) {
var search_input = tool_menu_frame.find("#tool-search-query");
search_input.val("search tools");
}
}
// Create GalaxyAsync object.
var GalaxyAsync = function(log_action) {
this.url_dict = {};
this.log_action = (log_action === undefined ? false : log_action);
};
GalaxyAsync.prototype.set_func_url = function( func_name, url ) {
this.url_dict[func_name] = url;
};
// Set user preference asynchronously.
GalaxyAsync.prototype.set_user_pref = function( pref_name, pref_value ) {
// Get URL.
var url = this.url_dict[arguments.callee];
if (url === undefined) { return false; }
$.ajax({
url: url,
data: { "pref_name" : pref_name, "pref_value" : pref_value },
error: function() { return false; },
success: function() { return true; }
});
};
// Log user action asynchronously.
GalaxyAsync.prototype.log_user_action = function( action, context, params ) {
if (!this.log_action) { return; }
// Get URL.
var url = this.url_dict[arguments.callee];
if (url === undefined) { return false; }
$.ajax({
url: url,
data: { "action" : action, "context" : context, "params" : params },
error: function() { return false; },
success: function() { return true; }
});
};
// Initialize refresh events.
function init_refresh_on_change () {
$("select[refresh_on_change='true']")
.off('change')
.change(function() {
var select_field = $(this),
select_val = select_field.val(),
refresh = false,
ref_on_change_vals = select_field.attr("refresh_on_change_values");
if (ref_on_change_vals) {
ref_on_change_vals = ref_on_change_vals.split(',');
var last_selected_value = select_field.attr("last_selected_value");
if ($.inArray(select_val, ref_on_change_vals) === -1 && $.inArray(last_selected_value, ref_on_change_vals) === -1) {
return;
}
}
$(window).trigger("refresh_on_change");
$(document).trigger("convert_to_values"); // Convert autocomplete text to values
select_field.get(0).form.submit();
});
// checkboxes refresh on change
$(":checkbox[refresh_on_change='true']")
.off('click')
.click( function() {
var select_field = $(this),
select_val = select_field.val(),
refresh = false,
ref_on_change_vals = select_field.attr("refresh_on_change_values");
if (ref_on_change_vals) {
ref_on_change_vals = ref_on_change_vals.split(',');
var last_selected_value = select_field.attr("last_selected_value");
if ($.inArray(select_val, ref_on_change_vals) === -1 && $.inArray(last_selected_value, ref_on_change_vals) === -1) {
return;
}
}
$(window).trigger("refresh_on_change");
select_field.get(0).form.submit();
});
// Links with confirmation
$( "a[confirm]" )
.off('click')
.click( function() {
return confirm( $(this).attr("confirm") );
});
};
// jQuery plugin to prevent double submission of forms
// Ref: http://stackoverflow.com/questions/2830542/prevent-double-submission-of-forms-in-jquery
jQuery.fn.preventDoubleSubmission = function() {
$(this).on('submit',function(e){
var $form = $(this);
if ($form.data('submitted') === true) {
// Previously submitted - don't submit again
e.preventDefault();
} else {
// Mark it so that the next submit can be ignored
$form.data('submitted', true);
}
});
// Keep chainability
return this;
};
$(document).ready( function() {
// Refresh events for form fields.
init_refresh_on_change();
// Tooltips
if ( $.fn.tooltip ) {
// Put tooltips below items in panel header so that they do not overlap masthead.
$(".unified-panel-header [title]").tooltip( { placement: 'bottom' } );
// default tooltip initialization, it will follow the data-placement tag for tooltip location
// and fallback to 'top' if not present
$("[title]").tooltip();
}
// Make popup menus.
make_popup_menus();
// Replace big selects.
replace_big_select_inputs(20, 1500);
// If galaxy_main frame does not exist and link targets galaxy_main,
// add use_panels=True and set target to self.
$("a").click( function() {
var anchor = $(this);
var galaxy_main_exists = (parent.frames && parent.frames.galaxy_main);
if ( ( anchor.attr( "target" ) == "galaxy_main" ) && ( !galaxy_main_exists ) ) {
var href = anchor.attr("href");
if (href.indexOf("?") == -1) {
href += "?";
}
else {
href += "&";
}
href += "use_panels=True";
anchor.attr("href", href);
anchor.attr("target", "_self");
}
return anchor;
});
});
-259
View File
@@ -1,259 +0,0 @@
// dependencies
define(["galaxy.masthead", "mvc/ui/ui-frames"], function(mod_masthead, Frames) {
/** Frame manager uses the ui-frames to create the scratch book masthead icon and functionality **/
var GalaxyFrame = Backbone.View.extend({
// base element
el_main: 'body',
// frame active/disabled
active: false,
// button active
button_active: null,
// button load
button_load : null,
// initialize
initialize : function(options) {
// add to masthead menu
var self = this;
// create frames
this.frames = new Frames.View({
visible: false,
});
// add activate icon
this.button_active = new mod_masthead.GalaxyMastheadIcon({
icon : 'fa-th',
tooltip : 'Enable/Disable Scratchbook',
onclick : function() { self._activate(); },
onunload : function() {
if (self.frames.length() > 0) {
return "You opened " + self.frames.length() + " frame(s) which will be lost.";
}
}
});
// add to masthead
Galaxy.masthead.append(this.button_active);
// add load icon
this.button_load = new mod_masthead.GalaxyMastheadIcon({
icon : 'fa-eye',
tooltip : 'Show/Hide Scratchbook',
onclick : function(e) {
if (self.frames.visible) {
self.frames.hide();
} else {
self.frames.show();
}
},
with_number : true
});
// add to masthead
Galaxy.masthead.append(this.button_load);
// create
this.setElement(this.frames.$el);
// append to main
$(this.el_main).append(this.$el);
// refresh menu
this.frames.setOnChange(function() {
self._refresh();
});
this._refresh();
},
/**
* Add a dataset to the frames.
*/
add_dataset: function(dataset_id) {
var self = this;
require(['mvc/data'], function(DATA) {
var dataset = new DATA.Dataset({ id: dataset_id });
$.when( dataset.fetch() ).then( function() {
// Construct frame config based on dataset's type.
var frame_config = {
title: dataset.get('name')
},
// HACK: For now, assume 'tabular' and 'interval' are the only
// modules that contain tabular files. This needs to be replaced
// will a is_datatype() function.
is_tabular = _.find(['tabular', 'interval'], function(data_type) {
return dataset.get('data_type').indexOf(data_type) !== -1;
});
// Use tabular chunked display if dataset is tabular; otherwise load via URL.
if (is_tabular) {
var tabular_dataset = new DATA.TabularDataset(dataset.toJSON());
_.extend(frame_config, {
type: 'other',
content: function( parent_elt ) {
DATA.createTabularDatasetChunkedView({
model: tabular_dataset,
parent_elt: parent_elt,
embedded: true,
height: '100%'
});
}
});
}
else {
_.extend(frame_config, {
type: 'url',
content: galaxy_config.root + 'datasets/' +
dataset.id + '/display/?preview=True'
});
}
self.add(frame_config);
});
});
},
/**
* Add a trackster visualization to the frames.
*/
add_trackster_viz: function(viz_id) {
var self = this;
require(['viz/visualization', 'viz/trackster'], function(visualization, trackster) {
var viz = new visualization.Visualization({id: viz_id});
$.when( viz.fetch() ).then( function() {
var ui = new trackster.TracksterUI(galaxy_config.root);
// Construct frame config based on dataset's type.
var frame_config = {
title: viz.get('name'),
type: 'other',
content: function(parent_elt) {
// Create view config.
var view_config = {
container: parent_elt,
name: viz.get('title'),
id: viz.id,
// FIXME: this will not work with custom builds b/c the dbkey needed to be encoded.
dbkey: viz.get('dbkey'),
stand_alone: false
},
latest_revision = viz.get('latest_revision'),
drawables = latest_revision.config.view.drawables;
// Set up datasets in drawables.
_.each(drawables, function(d) {
d.dataset = {
hda_ldda: d.hda_ldda,
id: d.dataset_id
};
});
view = ui.create_visualization(view_config,
latest_revision.config.viewport,
latest_revision.config.view.drawables,
latest_revision.config.bookmarks,
false);
}
};
self.add(frame_config);
});
});
},
/**
* Add and display a new frame/window based on options.
*/
add: function(options){
// open new tab
if (options.target == '_blank'){
window.open(options.content);
return;
}
// reload entire window
if (options.target == '_top' || options.target == '_parent' || options.target == '_self'){
window.location = options.content;
return;
}
// validate
if (!this.active){
// fix url if main frame is unavailable
var $galaxy_main = $(window.parent.document).find('#galaxy_main');
if (options.target == 'galaxy_main' || options.target == 'center'){
if ($galaxy_main.length === 0){
var href = options.content;
if (href.indexOf('?') == -1)
href += '?';
else
href += '&';
href += 'use_panels=True';
window.location = href;
} else {
$galaxy_main.attr('src', options.content);
}
} else
window.location = options.content;
// stop
return;
}
// add to frames view
this.frames.add(options);
},
// activate/disable panel
_activate: function (){
// check
if (this.active){
// disable
this.active = false;
// toggle
this.button_active.untoggle();
// hide panel
this.frames.hide();
} else {
// activate
this.active = true;
// untoggle
this.button_active.toggle();
}
},
// update frame counter
_refresh: function(){
// update on screen counter
this.button_load.number(this.frames.length());
// check
if(this.frames.length() === 0)
this.button_load.hide();
else
this.button_load.show();
// check
if (this.frames.visible) {
this.button_load.toggle();
} else {
this.button_load.untoggle();
}
}
});
// return
return {
GalaxyFrame: GalaxyFrame
};
});
@@ -1,11 +1,12 @@
define([
'libs/underscore',
'libs/backbone',
'mvc/base-mvc',
'mvc/user/user-model',
'utils/metrics-logger',
'utils/add-logging',
'utils/localization',
'mvc/base-mvc',
'bootstrapped-data'
], function( userModel, metricsLogger, addLogging, localize, BASE_MVC, bootstrapped ){
'utils/localization'
], function( _, Backbone, BASE_MVC, userModel, metricsLogger, addLogging, localize ){
// TODO: move into a singleton pattern and have dependents import Galaxy
// ============================================================================
@@ -17,9 +18,9 @@ define([
* galaxy.ini available from the configuration API)
* user : the current user (as a mvc/user/user-model)
*/
function GalaxyApp( options ){
function GalaxyApp( options, bootstrapped ){
var self = this;
return self._init( options || {} );
return self._init( options || {}, bootstrapped || {} );
}
// add logging shortcuts for this object
@@ -36,39 +37,38 @@ try {
}
/** initalize options and sub-components */
GalaxyApp.prototype._init = function init( options ){
GalaxyApp.prototype._init = function __init( options, bootstrapped ){
var self = this;
_.extend( self, Backbone.Events );
if( localDebugging ){
self.logger = console;
console.debug( 'debugging galaxy:', 'options:', options, 'bootstrapped:', bootstrapped );
}
self._processOptions( options );
self.debug( 'GalaxyApp.options: ', self.options );
self._initConfig( options.config || bootstrapped.config || {} );
self.debug( 'GalaxyApp.config: ', self.config );
// special case for root
self.root = options.root || '/';
self._initConfig( options.config || {} );
self._patchGalaxy( window.Galaxy );
self._initLogger( self.options.loggerOptions || {} );
// at this point, either logging or not and namespaces are enabled - chat it up
self.debug( 'GalaxyApp.options: ', self.options );
self.debug( 'GalaxyApp.config: ', self.config );
self.debug( 'GalaxyApp.logger: ', self.logger );
self._initLocale();
self.debug( 'GalaxyApp.localize: ', self.localize );
self._initUser( options.user || bootstrapped.user || {} );
self.config = options.config || {};
self.debug( 'GalaxyApp.config: ', self.config );
self._initUser( options.user || {} );
self.debug( 'GalaxyApp.user: ', self.user );
self.root = options.root;
self.debug( 'GalaxyApp.root: ', self.root );
//TODO: temp
self.trigger( 'ready', self );
//if( typeof options.onload === 'function' ){
// options.onload();
//}
self._setUpListeners();
self.trigger( 'ready', self );
return self;
};
@@ -78,16 +78,13 @@ GalaxyApp.prototype.defaultOptions = {
/** monkey patch attributes from existing window.Galaxy object? */
patchExisting : true,
/** root url of this app */
root : '/',
/** options for the logger */
loggerOptions : {}
root : '/'
};
/** add an option from options if the key matches an option in defaultOptions */
/** filter to options present in defaultOptions (and default to them) */
GalaxyApp.prototype._processOptions = function _processOptions( options ){
var self = this,
defaults = self.defaultOptions;
self.debug( '_processOptions: ', options );
self.options = {};
for( var k in defaults ){
@@ -101,7 +98,6 @@ GalaxyApp.prototype._processOptions = function _processOptions( options ){
/** parse the config and any extra info derived from it */
GalaxyApp.prototype._initConfig = function _initConfig( config ){
var self = this;
self.debug( '_initConfig: ', config );
self.config = config;
// give precendence to localdebugging for this setting
@@ -111,16 +107,16 @@ GalaxyApp.prototype._initConfig = function _initConfig( config ){
};
/** add an option from options if the key matches an option in defaultOptions */
GalaxyApp.prototype._patchGalaxy = function _processOptions( patchWith ){
GalaxyApp.prototype._patchGalaxy = function _patchGalaxy( patchWith ){
var self = this;
// in case req or plain script tag order has created a prev. version of the Galaxy obj...
if( self.options.patchExisting && patchWith ){
self.debug( 'found existing Galaxy object:', patchWith );
// self.debug( 'found existing Galaxy object:', patchWith );
// ...(for now) monkey patch any added attributes that the previous Galaxy may have had
//TODO: move those attributes to more formal assignment in GalaxyApp
for( var k in patchWith ){
if( patchWith.hasOwnProperty( k ) ){
self.debug( '\t patching in ' + k + ' to Galaxy' );
// self.debug( '\t patching in ' + k + ' to Galaxy:', self[ k ] );
self[ k ] = patchWith[ k ];
}
}
@@ -130,6 +126,7 @@ GalaxyApp.prototype._patchGalaxy = function _processOptions( patchWith ){
/** set up the metrics logger (utils/metrics-logger) and pass loggerOptions */
GalaxyApp.prototype._initLogger = function _initLogger( loggerOptions ){
var self = this;
// default to console logging at the debug level if the debug flag is set
if( self.config.debug ){
loggerOptions.consoleLogger = loggerOptions.consoleLogger || console;
@@ -139,11 +136,13 @@ GalaxyApp.prototype._initLogger = function _initLogger( loggerOptions ){
loggerOptions.consoleNamespaceWhitelist = localStorage.getItem( NAMESPACE_KEY ).split( ',' );
} catch( storageErr ){}
}
self.debug( '_initLogger:', loggerOptions );
self.logger = new metricsLogger.MetricsLogger( loggerOptions );
self.emit = {};
[ 'log', 'debug', 'info', 'warn', 'error', 'metric' ].map(function( i ) {
self.emit[ i ] = function( data ) { self.logger.emit( i, arguments[ 0 ], Array.prototype.slice.call( arguments, 1 ) ) };
self.emit[ i ] = function( data ){
self.logger.emit( i, arguments[ 0 ], Array.prototype.slice.call( arguments, 1 ) );
};
});
if( self.config.debug ){
@@ -159,6 +158,7 @@ GalaxyApp.prototype._initLocale = function _initLocale( options ){
self.debug( '_initLocale:', options );
self.localize = localize;
// add to window as global shortened alias
// TODO: temporary - remove when can require for plugins
window._l = self.localize;
return self;
};
@@ -169,8 +169,6 @@ GalaxyApp.prototype._initUser = function _initUser( userJSON ){
self.debug( '_initUser:', userJSON );
self.user = new userModel.User( userJSON );
self.user.logger = self.logger;
//TODO: temp - old alias
self.currUser = self.user;
return self;
};
@@ -251,7 +249,6 @@ GalaxyApp.prototype.toString = function toString(){
return 'GalaxyApp(' + userEmail + ')';
};
// ============================================================================
return {
GalaxyApp : GalaxyApp
+6 -6
View File
@@ -3,7 +3,7 @@
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
define([
"galaxy.masthead",
"layout/masthead",
"utils/utils",
"libs/toastr",
"mvc/base-mvc",
@@ -32,7 +32,7 @@ define([
// ============================================================================
/**
* The Data Libraries router. Takes care about triggering routes
* The Data Libraries router. Takes care about triggering routes
* and sends users to proper pieces of the application.
*/
var LibraryRouter = Backbone.Router.extend({
@@ -83,7 +83,7 @@ var LibraryRouter = Backbone.Router.extend({
url = "/" + url;
}
if ( typeof ga !== 'undefined' ) {
ga( 'send', 'pageview', galaxy_config.root + 'library/list' + url );
ga( 'send', 'pageview', Galaxy.root + 'library/list' + url );
}
}
});
@@ -140,7 +140,7 @@ var GalaxyLibrary = Backbone.View.extend({
Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView();
Galaxy.libraries.libraryListView = new mod_librarylist_view.LibraryListView();
});
this.library_router.on('route:libraries_page', function( show_page ) {
if ( Galaxy.libraries.libraryToolbarView === null ){
Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView();
@@ -151,7 +151,7 @@ var GalaxyLibrary = Backbone.View.extend({
});
this.library_router.on( 'route:folder_content', function( id ) {
if (Galaxy.libraries.folderToolbarView){
if (Galaxy.libraries.folderToolbarView){
Galaxy.libraries.folderToolbarView.$el.unbind( 'click' );
}
Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( { id: id } );
@@ -181,7 +181,7 @@ var GalaxyLibrary = Backbone.View.extend({
if (Galaxy.libraries.datasetView){
Galaxy.libraries.datasetView.$el.unbind('click');
}
Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id});
Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, show_version: false, show_permissions: false});
});
this.library_router.on( 'route:dataset_version', function(folder_id, dataset_id, ldda_id){
-420
View File
@@ -1,420 +0,0 @@
// dependencies
define([], function() {
/** Masthead **/
var GalaxyMasthead = Backbone.View.extend({
// base element
el_masthead: '#everything',
// options
options : null,
// background
$background: null,
// list
list: [],
// initialize
initialize : function(options) {
// update options
this.options = options;
// HACK: due to body events defined in galaxy.panels.js
$("body").off();
// define this element
this.setElement($(this._template(options)));
// append to masthead
$(this.el_masthead).append($(this.el));
// assign background
this.$background = $(this.el).find('#masthead-background');
// loop through unload functions if the user attempts to unload the page
var self = this;
$(window).on('beforeunload', function() {
var text = "";
for (key in self.list) {
if (self.list[key].options.onunload) {
var q = self.list[key].options.onunload();
if (q) text += q + " ";
}
}
if (text != "") {
return text;
}
});
},
// configure events
events: {
'click' : '_click',
'mousedown' : function(e) { e.preventDefault() }
},
// adds a new item to the masthead
append : function(item) {
return this._add(item, true);
},
// adds a new item to the masthead
prepend : function(item) {
return this._add(item, false);
},
// activate
highlight: function(id) {
var current = $(this.el).find('#' + id + '> li');
if (current) {
current.addClass('active');
}
},
// adds a new item to the masthead
_add : function(item, append) {
var $loc = $(this.el).find('#' + item.location);
if ($loc){
// create frame for new item
var $current = $(item.el);
// configure class in order to mark new items
$current.addClass('masthead-item');
// append to masthead
if (append) {
$loc.append($current);
} else {
$loc.prepend($current);
}
// add to list
this.list.push(item);
}
// location not found
return null;
},
// handle click event
_click: function(e) {
// close all popups
var $all = $(this.el).find('.popup');
if ($all) {
$all.hide();
}
// open current item
var $current = $(e.target).closest('.masthead-item').find('.popup');
if ($(e.target).hasClass('head')) {
$current.show();
this.$background.show();
} else {
this.$background.hide();
}
},
/*
HTML TEMPLATES
*/
// fill template
_template: function(options) {
var brand_text = options.brand ? ("/ " + options.brand) : "" ;
return '<div><div id="masthead" class="navbar navbar-fixed-top navbar-inverse">' +
'<div style="position: relative; right: -50%; float: left;">' +
'<div id="navbar" style="display: block; position: relative; right: 50%;"></div>' +
'</div>' +
'<div class="navbar-brand">' +
'<a href="' + options.logo_url + '">' +
'<img style="margin-left: 0.35em;" border="0" src="' + galaxy_config.root + 'static/images/galaxyIcon_noText.png">' +
'<span id="brand"> Galaxy ' + brand_text + '</span>' +
'</a>' +
'</div>' +
'<div class="quota-meter-container"></div>' +
'<div id="iconbar" class="iconbar"></div>' +
'</div>' +
'<div id="masthead-background" style="display: none; position: absolute; top: 33px; width: 100%; height: 100%; z-index: 1010"></div>' +
'</div>';
}
});
/** Masthead icon **/
var GalaxyMastheadIcon = Backbone.View.extend({
// icon options
options:{
id : '',
icon : 'fa-cog',
tooltip : '',
with_number : false,
onclick : function() { alert ('clicked') },
onunload : null,
visible : true
},
// location identifier for masthead class
location: 'iconbar',
// initialize
initialize: function (options){
// read in defaults
if (options)
this.options = _.defaults(options, this.options);
// add template for icon
this.setElement($(this._template(this.options)));
// configure icon
var self = this;
$(this.el).find('.icon').tooltip({title: this.options.tooltip, placement: 'bottom'})
.on('mouseup', self.options.onclick);
// visiblity
if (!this.options.visible)
this.hide();
},
// show
show: function(){
$(this.el).css({visibility : 'visible'});
},
// show
hide: function(){
$(this.el).css({visibility : 'hidden'});
},
// switch icon
icon: function (new_icon){
// update icon class
$(this.el).find('.icon').removeClass(this.options.icon)
.addClass(new_icon);
// update icon
this.options.icon = new_icon;
},
// toggle
toggle: function(){
$(this.el).addClass('toggle');
},
// untoggle
untoggle: function(){
$(this.el).removeClass('toggle');
},
// set/get number
number: function(new_number){
$(this.el).find('.number').text(new_number);
},
// fill template icon
_template: function (options){
var tmpl = '<div id="' + options.id + '" class="symbol">' +
'<div class="icon fa fa-2x ' + options.icon + '"></div>';
if (options.with_number)
tmpl+= '<div class="number"></div>';
tmpl += '</div>';
// return template
return tmpl;
}
});
/** Masthead tab **/
var GalaxyMastheadTab = Backbone.View.extend({
// main options
options:{
id : '',
title : '',
target : '_parent',
content : '',
type : 'url',
scratchbook : false,
onunload : null,
visible : true,
disabled : false,
title_attribute : ''
},
// location
location: 'navbar',
// optional sub menu
$menu: null,
// events
events:{
'click .head' : '_head'
},
// initialize
initialize: function ( options ){
// read in defaults
if ( options ){
this.options = _.defaults( options, this.options );
}
// update url
if ( this.options.content !== undefined && this.options.content.indexOf( '//' ) === -1 ){
this.options.content = galaxy_config.root + this.options.content;
}
// add template for tab
this.setElement( $( this._template( this.options ) ) );
// disable menu items that are not available to anonymous user
// also show title to explain why they are disabled
if ( this.options.disabled ){
$( this.el ).find( '.root' ).addClass( 'disabled' );
this._attachPopover();
}
// visiblity
if ( !this.options.visible ){
this.hide();
}
},
// show
show: function(){
$(this.el).css({visibility : 'visible'});
},
// show
hide: function(){
$(this.el).css({visibility : 'hidden'});
},
// add menu item
add: function (options){
// menu option defaults
var menuOptions = {
title : 'Title',
content : '',
type : 'url',
target : '_parent',
scratchbook : false,
divider : false,
onclick : undefined
}
// read in defaults
if (options)
menuOptions = _.defaults(options, menuOptions);
// update url
if (menuOptions.content && menuOptions.content.indexOf('//') === -1)
menuOptions.content = galaxy_config.root + menuOptions.content;
// check if submenu element is available
if (!this.$menu){
// insert submenu element into root
$(this.el).find('.root').append(this._templateMenu());
// show caret
$(this.el).find('.symbol').addClass('caret');
// update element link
this.$menu = $(this.el).find('.popup');
}
// create
var $item = $(this._templateMenuItem(menuOptions));
// append menu
this.$menu.append($item);
// add events
var self = this;
if (menuOptions.onclick !== undefined){
$item.on('click', function(e){
e.preventDefault();
menuOptions.onclick();
});
} else {
$item.on('click', function(e){
// prevent default
e.preventDefault();
// no modifications if new tab is requested
if (self.options.target === '_blank')
return true;
// load into frame
Galaxy.frame.add(options);
});
}
// append divider
if (menuOptions.divider)
this.$menu.append($(this._templateDivider()));
},
// show menu on header click
_head: function(e){
// prevent default
e.preventDefault();
if (this.options.disabled){
return // prevent link following if menu item is disabled
}
// check for menu options
if (!this.$menu) {
Galaxy.frame.add(this.options);
}
},
_attachPopover : function(){
var $popover_element = $(this.el).find('.head');
$popover_element.popover({
html: true,
content: 'Please <a href="' + galaxy_config.root + 'user/login?use_panels=True">log in</a> or <a href="' + galaxy_config.root + 'user/create?use_panels=True">register</a> to use this feature.',
placement: 'bottom'
}).on('shown.bs.popover', function() { // hooking on bootstrap event to automatically hide popovers after delay
setTimeout(function() {
$popover_element.popover('hide');
}, 5000);
});
},
// fill template header
_templateMenuItem: function (options){
return '<li><a href="' + options.content + '" target="' + options.target + '">' + options.title + '</a></li>';
},
// fill template header
_templateMenu: function (){
return '<ul class="popup dropdown-menu"></ul>';
},
_templateDivider: function(){
return '<li class="divider"></li>';
},
// fill template
_template: function (options){
// start template
var tmpl = '<ul id="' + options.id + '" class="nav navbar-nav" border="0" cellspacing="0">' +
'<li class="root dropdown" style="">' +
'<a class="head dropdown-toggle" data-toggle="dropdown" target="' + options.target + '" href="' + options.content + '" title="' + options.title_attribute + '">' +
options.title + '<b class="symbol"></b>' +
'</a>' +
'</li>' +
'</ul>';
// return template
return tmpl;
}
});
// return
return {
GalaxyMasthead: GalaxyMasthead,
GalaxyMastheadTab: GalaxyMastheadTab,
GalaxyMastheadIcon: GalaxyMastheadIcon
};
});
-322
View File
@@ -1,322 +0,0 @@
// dependencies
define(['galaxy.masthead'], function( Masthead ) {
/** GalaxyMenu uses the GalaxyMasthead class in order to add menu items and icons to the Masthead **/
var GalaxyMenu = Backbone.Model.extend({
initialize: function( options ) {
this.options = options.config;
this.masthead = options.masthead;
this.create();
},
// default menu
create: function() {
//
// Analyze data tab.
//
var tab_analysis = new Masthead.GalaxyMastheadTab({
id : 'analysis',
title : 'Analyze Data',
content : '',
title_attribute : 'Analysis home view'
});
this.masthead.append( tab_analysis );
//
// Workflow tab.
//
var workflow_options = {
id : 'workflow',
title : 'Workflow',
content : 'workflow',
title_attribute : 'Chain tools into workflows'
}
if ( !Galaxy.user.id ) {
workflow_options.disabled = true; // disable workflows for anonymous users
}
var tab_workflow = new Masthead.GalaxyMastheadTab( workflow_options );
this.masthead.append( tab_workflow );
//
// 'Shared Items' or Libraries tab.
//
var tab_shared = new Masthead.GalaxyMastheadTab({
id : 'shared',
title : 'Shared Data',
content : 'library/index',
title_attribute : 'Access published resources'
});
tab_shared.add({
title : 'Data Libraries deprecated',
content : 'library/index'
});
tab_shared.add({
title : 'Data Libraries',
content : 'library/list',
divider : true
});
tab_shared.add({
title : 'Published Histories',
content : 'history/list_published'
});
tab_shared.add({
title : 'Published Workflows',
content : 'workflow/list_published'
});
tab_shared.add({
title : 'Published Visualizations',
content : 'visualization/list_published'
});
tab_shared.add({
title : 'Published Pages',
content : 'page/list_published'
});
this.masthead.append(tab_shared);
//
// Lab menu.
//
if ( this.options.user_requests ) {
var tab_lab = new Masthead.GalaxyMastheadTab({
id : 'lab',
title : 'Lab'
});
tab_lab.add({
title : 'Sequencing Requests',
content : 'requests/index'
});
tab_lab.add({
title : 'Find Samples',
content : 'requests/find_samples_index'
});
tab_lab.add({
title : 'Help',
content : this.options.lims_doc_url
});
this.masthead.append( tab_lab );
}
//
// Visualization tab.
//
var visualization_options = {
id : 'visualization',
title : 'Visualization',
content : 'visualization/list',
title_attribute : 'Visualize datasets'
}
// disable visualizations for anonymous users
if ( !Galaxy.user.id ) {
visualization_options.disabled = true;
}
var tab_visualization = new Masthead.GalaxyMastheadTab( visualization_options );
// add submenu only when user is logged in
if ( Galaxy.user.id ) {
tab_visualization.add({
title : 'New Track Browser',
content : 'visualization/trackster',
target : '_frame'
});
tab_visualization.add({
title : 'Saved Visualizations',
content : 'visualization/list',
target : '_frame'
});
}
this.masthead.append( tab_visualization );
//
// Admin.
//
if ( Galaxy.user.get( 'is_admin' ) ) {
var tab_admin = new Masthead.GalaxyMastheadTab({
id : 'admin',
title : 'Admin',
content : 'admin',
extra_class : 'admin-only',
title_attribute : 'Administer this Galaxy'
});
this.masthead.append( tab_admin );
}
//
// Help tab.
//
var tab_help = new Masthead.GalaxyMastheadTab({
id : 'help',
title : 'Help',
title_attribute : 'Support, contact, and community hubs'
});
if ( this.options.biostar_url ){
tab_help.add({
title : 'Galaxy Biostar',
content : this.options.biostar_url_redirect,
target : '_blank'
});
tab_help.add({
title : 'Ask a question',
content : 'biostar/biostar_question_redirect',
target : '_blank'
});
}
tab_help.add({
title : 'Support',
content : this.options.support_url,
target : '_blank'
});
tab_help.add({
title : 'Search',
content : this.options.search_url,
target : '_blank'
});
tab_help.add({
title : 'Mailing Lists',
content : this.options.mailing_lists,
target : '_blank'
});
tab_help.add({
title : 'Videos',
content : this.options.screencasts_url,
target : '_blank'
});
tab_help.add({
title : 'Wiki',
content : this.options.wiki_url,
target : '_blank'
});
tab_help.add({
title : 'How to Cite Galaxy',
content : this.options.citation_url,
target : '_blank'
});
if (this.options.terms_url){
tab_help.add({
title : 'Terms and Conditions',
content : this.options.terms_url,
target : '_blank'
});
}
this.masthead.append( tab_help );
//
// User tab.
//
if ( !Galaxy.user.id ){
var tab_user = new Masthead.GalaxyMastheadTab({
id : 'user',
title : 'User',
extra_class : 'loggedout-only',
title_attribute : 'Account registration or login'
});
// login
tab_user.add({
title : 'Login',
content : 'user/login',
target : 'galaxy_main'
});
// register
if ( this.options.allow_user_creation ){
tab_user.add({
title : 'Register',
content : 'user/create',
target : 'galaxy_main'
});
}
// add to masthead
this.masthead.append( tab_user );
} else {
var tab_user = new Masthead.GalaxyMastheadTab({
id : 'user',
title : 'User',
extra_class : 'loggedin-only',
title_attribute : 'Account preferences and saved data'
});
// show user logged in info
tab_user.add({
title : 'Logged in as ' + Galaxy.user.get( 'email' )
});
tab_user.add({
title : 'Preferences',
content : 'user?cntrller=user',
target : 'galaxy_main'
});
tab_user.add({
title : 'Custom Builds',
content : 'user/dbkeys',
target : 'galaxy_main'
});
tab_user.add({
title : 'Logout',
content : 'user/logout',
target : '_top',
divider : true
});
// default tabs
tab_user.add({
title : 'Saved Histories',
content : 'history/list',
target : 'galaxy_main'
});
tab_user.add({
title : 'Saved Datasets',
content : 'dataset/list',
target : 'galaxy_main'
});
tab_user.add({
title : 'Saved Pages',
content : 'page/list',
target : '_top'
});
tab_user.add({
title : 'API Keys',
content : 'user/api_keys?cntrller=user',
target : 'galaxy_main'
});
if ( this.options.use_remote_user ){
tab_user.add({
title : 'Public Name',
content : 'user/edit_username?cntrller=user',
target : 'galaxy_main'
});
}
// add to masthead
this.masthead.append( tab_user );
}
// identify active tab
if ( this.options.active_view ) {
this.masthead.highlight( this.options.active_view );
}
}
});
// return
return {
GalaxyMenu: GalaxyMenu
};
});
+108 -108
View File
@@ -1,5 +1,5 @@
// Useful Galaxy stuff.
var Galaxy =
var CONTROLS =
{
// Item types.
ITEM_HISTORY : "item_history",
@@ -7,14 +7,14 @@ var Galaxy =
ITEM_WORKFLOW : "item_workflow",
ITEM_PAGE : "item_page",
ITEM_VISUALIZATION : "item_visualization",
// Link dialogs.
DIALOG_HISTORY_LINK : "link_history",
DIALOG_DATASET_LINK : "link_dataset",
DIALOG_WORKFLOW_LINK : "link_workflow",
DIALOG_PAGE_LINK : "link_page",
DIALOG_VISUALIZATION_LINK : "link_visualization",
// Embed dialogs.
DIALOG_EMBED_HISTORY : "embed_history",
DIALOG_EMBED_DATASET : "embed_dataset",
@@ -24,10 +24,10 @@ var Galaxy =
};
// Initialize Galaxy elements.
function init_galaxy_elts(wym)
function init_galaxy_elts(wym)
{
// Set up events to make annotation easy.
$('.annotation', wym._doc.body).each( function()
$('.annotation', wym._doc.body).each( function()
{
$(this).click( function() {
// Works in Safari, not in Firefox.
@@ -39,53 +39,53 @@ function init_galaxy_elts(wym)
var t = "";
});
});
};
// Based on the dialog type, return a dictionary of information about an item
function get_item_info( dialog_type )
{
var
item_singular,
item_plural,
item_singular,
item_plural,
item_controller;
switch( dialog_type ) {
case( Galaxy.ITEM_HISTORY ):
case( CONTROLS.ITEM_HISTORY ):
item_singular = "History";
item_plural = "Histories";
item_controller = "history";
item_class = "History";
break;
case( Galaxy.ITEM_DATASET ):
case( CONTROLS.ITEM_DATASET ):
item_singular = "Dataset";
item_plural = "Datasets";
item_controller = "dataset";
item_class = "HistoryDatasetAssociation";
break;
case( Galaxy.ITEM_WORKFLOW ):
case( CONTROLS.ITEM_WORKFLOW ):
item_singular = "Workflow";
item_plural = "Workflows";
item_controller = "workflow";
item_class = "StoredWorkflow";
break;
case( Galaxy.ITEM_PAGE ):
case( CONTROLS.ITEM_PAGE ):
item_singular = "Page";
item_plural = "Pages";
item_controller = "page";
item_class = "Page";
break;
case( Galaxy.ITEM_VISUALIZATION ):
case( CONTROLS.ITEM_VISUALIZATION ):
item_singular = "Visualization";
item_plural = "Visualizations";
item_controller = "visualization";
item_class = "Visualization";
break;
}
// Build ajax URL that lists items for selection.
var item_list_action = "list_" + item_plural.toLowerCase() + "_for_selection";
var ajax_url = list_objects_url.replace( "LIST_ACTION", item_list_action );
// Set up and return dict.
return {
singular : item_singular,
@@ -110,31 +110,31 @@ function make_item_importable( item_controller, item_id, item_type )
// Completely replace WYM's dialog handling
WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHtml ) {
var wym = this;
var sStamp = wym.uniqueStamp();
var selected = wym.selected();
// Swap out URL attribute for id/name attribute in link creation to enable anchor creation in page.
function set_link_id()
function set_link_id()
{
// When "set link id" link clicked, update UI.
$('#set_link_id').click( function()
$('#set_link_id').click( function()
{
// Set label.
$("#link_attribute_label").text("ID/Name");
// Set input elt class, value.
var attribute_input = $(".wym_href");
attribute_input.addClass("wym_id").removeClass("wym_href");
if (selected)
attribute_input.val( $(selected).attr('id') );
// Remove link.
$(this).remove();
});
}
// LINK DIALOG
if ( dialogType == WYMeditor.DIALOG_LINK ) {
if(selected) {
@@ -164,11 +164,11 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
var sUrl = $(wym._options.hrefSelector).val() || '',
sId = $(".wym_id").val() || '',
sName = $(wym._options.titleSelector).val() || '';
if (sUrl || sId) {
// Create link.
wym._exec(WYMeditor.CREATE_LINK, sStamp);
// Set link attributes.
var link = $("a[href=" + sStamp + "]", wym._doc.body);
link.attr(WYMeditor.HREF, sUrl)
@@ -190,7 +190,7 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
set_link_id
);
}
// IMAGE DIALOG
if ( dialogType == WYMeditor.DIALOG_IMAGE ) {
if(wym._selected_image) {
@@ -216,7 +216,7 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
+ "<input type='text' class='wym_title' value='' size='40' />"
+ "</div>",
{
"Insert": function() {
"Insert": function() {
var sUrl = $(wym._options.srcSelector).val();
if(sUrl.length > 0) {
wym._exec(WYMeditor.INSERT_IMAGE, sStamp);
@@ -234,7 +234,7 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
);
return;
}
// TABLE DIALOG
if ( dialogType == WYMeditor.DIALOG_TABLE ) {
show_modal(
@@ -259,29 +259,29 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
"Insert": function() {
var iRows = $(wym._options.rowsSelector).val();
var iCols = $(wym._options.colsSelector).val();
if(iRows > 0 && iCols > 0) {
var table = wym._doc.createElement(WYMeditor.TABLE);
var newRow = null;
var newCol = null;
var sCaption = $(wym._options.captionSelector).val();
//we create the caption
var newCaption = table.createCaption();
newCaption.innerHTML = sCaption;
//we create the rows and cells
for(x=0; x<iRows; x++) {
newRow = table.insertRow(x);
for(y=0; y<iCols; y++) {newRow.insertCell(y);}
}
//set the summary attr
$(table).attr('summary',
$(wym._options.summarySelector).val());
//append the table after the selected container
var node = $(wym.findUp(wym.container(),
WYMeditor.MAIN_CONTAINERS)).get(0);
@@ -296,38 +296,38 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
}
);
}
// INSERT "GALAXY ITEM" LINK DIALOG
if ( dialogType == Galaxy.DIALOG_HISTORY_LINK || dialogType == Galaxy.DIALOG_DATASET_LINK ||
dialogType == Galaxy.DIALOG_WORKFLOW_LINK || dialogType == Galaxy.DIALOG_PAGE_LINK ||
dialogType == Galaxy.DIALOG_VISUALIZATION_LINK ) {
if ( dialogType == CONTROLS.DIALOG_HISTORY_LINK || dialogType == CONTROLS.DIALOG_DATASET_LINK ||
dialogType == CONTROLS.DIALOG_WORKFLOW_LINK || dialogType == CONTROLS.DIALOG_PAGE_LINK ||
dialogType == CONTROLS.DIALOG_VISUALIZATION_LINK ) {
// Based on item type, set useful vars.
var item_info;
switch(dialogType)
{
case(Galaxy.DIALOG_HISTORY_LINK):
item_info = get_item_info(Galaxy.ITEM_HISTORY);
case(CONTROLS.DIALOG_HISTORY_LINK):
item_info = get_item_info(CONTROLS.ITEM_HISTORY);
break;
case(Galaxy.DIALOG_DATASET_LINK):
item_info = get_item_info(Galaxy.ITEM_DATASET);
case(CONTROLS.DIALOG_DATASET_LINK):
item_info = get_item_info(CONTROLS.ITEM_DATASET);
break;
case(Galaxy.DIALOG_WORKFLOW_LINK):
item_info = get_item_info(Galaxy.ITEM_WORKFLOW);
case(CONTROLS.DIALOG_WORKFLOW_LINK):
item_info = get_item_info(CONTROLS.ITEM_WORKFLOW);
break;
case(Galaxy.DIALOG_PAGE_LINK):
item_info = get_item_info(Galaxy.ITEM_PAGE);
case(CONTROLS.DIALOG_PAGE_LINK):
item_info = get_item_info(CONTROLS.ITEM_PAGE);
break;
case(Galaxy.DIALOG_VISUALIZATION_LINK):
item_info = get_item_info(Galaxy.ITEM_VISUALIZATION);
case(CONTROLS.DIALOG_VISUALIZATION_LINK):
item_info = get_item_info(CONTROLS.ITEM_VISUALIZATION);
break;
}
$.ajax(
{
url: item_info.list_ajax_url,
data: {},
error: function() { alert( "Failed to list " + item_info.plural.toLowerCase() + " for selection"); },
success: function(table_html)
success: function(table_html)
{
show_modal(
"Insert Link to " + item_info.singular,
@@ -336,22 +336,22 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
"Make the selected " + item_info.plural.toLowerCase() + " accessible so that they can viewed by everyone.</div>"
,
{
"Insert": function()
"Insert": function()
{
// Make selected items accessible (importable) ?
var make_importable = false;
if ( $('#make-importable:checked').val() !== null )
make_importable = true;
// Insert links to history for each checked item.
var item_ids = new Array();
$('input[name=id]:checked').each(function() {
var item_id = $(this).val();
// Make item importable?
if (make_importable)
make_item_importable(item_info.controller, item_id, item_info.singular);
// Insert link(s) to item(s). This is done by getting item info and then manipulating wym.
url_template = get_name_and_link_url + item_id;
ajax_url = url_template.replace( "ITEM_CONTROLLER", item_info.controller);
@@ -359,7 +359,7 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
// Get link text.
wym._exec(WYMeditor.CREATE_LINK, sStamp);
var link_text = $("a[href=" + sStamp + "]", wym._doc.body).text();
// Insert link: need to do different actions depending on link text.
if (
link_text == "" // Firefox.
@@ -375,12 +375,12 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
// Link created from selected text; add href and title.
$("a[href=" + sStamp + "]", wym._doc.body).attr(WYMeditor.HREF, returned_item_info.link).attr(WYMeditor.TITLE, item_info.singular + item_id);
}
});
});
});
hide_modal();
},
"Cancel": function()
"Cancel": function()
{
hide_modal();
}
@@ -390,62 +390,62 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
});
}
// EMBED GALAXY OBJECT DIALOGS
if ( dialogType == Galaxy.DIALOG_EMBED_HISTORY || dialogType == Galaxy.DIALOG_EMBED_DATASET || dialogType == Galaxy.DIALOG_EMBED_WORKFLOW || dialogType == Galaxy.DIALOG_EMBED_PAGE || dialogType == Galaxy.DIALOG_EMBED_VISUALIZATION ) {
if ( dialogType == CONTROLS.DIALOG_EMBED_HISTORY || dialogType == CONTROLS.DIALOG_EMBED_DATASET || dialogType == CONTROLS.DIALOG_EMBED_WORKFLOW || dialogType == CONTROLS.DIALOG_EMBED_PAGE || dialogType == CONTROLS.DIALOG_EMBED_VISUALIZATION ) {
// Based on item type, set useful vars.
var item_info;
switch(dialogType)
{
case(Galaxy.DIALOG_EMBED_HISTORY):
item_info = get_item_info(Galaxy.ITEM_HISTORY);
case(CONTROLS.DIALOG_EMBED_HISTORY):
item_info = get_item_info(CONTROLS.ITEM_HISTORY);
break;
case(Galaxy.DIALOG_EMBED_DATASET):
item_info = get_item_info(Galaxy.ITEM_DATASET);
case(CONTROLS.DIALOG_EMBED_DATASET):
item_info = get_item_info(CONTROLS.ITEM_DATASET);
break;
case(Galaxy.DIALOG_EMBED_WORKFLOW):
item_info = get_item_info(Galaxy.ITEM_WORKFLOW);
case(CONTROLS.DIALOG_EMBED_WORKFLOW):
item_info = get_item_info(CONTROLS.ITEM_WORKFLOW);
break;
case(Galaxy.DIALOG_EMBED_PAGE):
item_info = get_item_info(Galaxy.ITEM_PAGE);
case(CONTROLS.DIALOG_EMBED_PAGE):
item_info = get_item_info(CONTROLS.ITEM_PAGE);
break;
case(Galaxy.DIALOG_EMBED_VISUALIZATION):
item_info = get_item_info(Galaxy.ITEM_VISUALIZATION);
case(CONTROLS.DIALOG_EMBED_VISUALIZATION):
item_info = get_item_info(CONTROLS.ITEM_VISUALIZATION);
break;
}
$.ajax(
{
url: item_info.list_ajax_url,
data: {},
error: function() { alert( "Failed to list " + item_info.plural.toLowerCase() + " for selection"); },
success: function(list_html)
success: function(list_html)
{
// Can make histories, workflows importable; cannot make datasets importable.
if (dialogType == Galaxy.DIALOG_EMBED_HISTORY || dialogType == Galaxy.DIALOG_EMBED_WORKFLOW
|| dialogType == Galaxy.DIALOG_EMBED_VISUALIZATION)
if (dialogType == CONTROLS.DIALOG_EMBED_HISTORY || dialogType == CONTROLS.DIALOG_EMBED_WORKFLOW
|| dialogType == CONTROLS.DIALOG_EMBED_VISUALIZATION)
list_html = list_html + "<div><input id='make-importable' type='checkbox' checked/>" +
"Make the selected " + item_info.plural.toLowerCase() + " accessible so that they can viewed by everyone.</div>";
show_modal(
"Embed " + item_info.plural,
list_html,
{
"Embed": function()
{
"Embed": function()
{
// Make selected items accessible (importable) ?
var make_importable = false;
if ( $('#make-importable:checked').val() != null )
make_importable = true;
$('input[name=id]:checked').each(function() {
// Get item ID and name.
var item_id = $(this).val();
// Use ':first' because there are many labels in table; the first one is the item name.
var item_name = $("label[for='" + item_id + "']:first").text();
if (make_importable)
make_item_importable(item_info.controller, item_id, item_info.singular);
// Embedded item HTML; item class is embedded in div container classes; this is necessary because the editor strips
// all non-standard attributes when it returns its content (e.g. it will not return an element attribute of the form
// Embedded item HTML; item class is embedded in div container classes; this is necessary because the editor strips
// all non-standard attributes when it returns its content (e.g. it will not return an element attribute of the form
// item_class='History').
var item_elt_id = item_info.iclass + "-" + item_id;
var item_embed_html = [
@@ -459,14 +459,14 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
item_info.singular.toLowerCase(), " when it is displayed.]",
"</p>",
"</div>" ].join( '' );
// Insert embedded item into document.
wym.insert(item_embed_html);
});
hide_modal();
},
"Cancel": function()
"Cancel": function()
{
hide_modal();
}
@@ -491,7 +491,7 @@ $(function(){
basePath: editor_base_path,
iframeBasePath: iframe_base_path,
boxHtml: "<table class='wym_box' width='100%' height='100%'>"
+ "<tr><td><div class='wym_area_top'>"
+ "<tr><td><div class='wym_area_top'>"
+ WYMeditor.TOOLS
+ "</div></td></tr>"
+ "<tr height='100%'><td>"
@@ -503,7 +503,7 @@ $(function(){
+ "</div>"
+ "</td></tr></table>",
toolsItems: [
{'name': 'Bold', 'title': 'Strong', 'css': 'wym_tools_strong'},
{'name': 'Bold', 'title': 'Strong', 'css': 'wym_tools_strong'},
{'name': 'Italic', 'title': 'Emphasis', 'css': 'wym_tools_emphasis'},
{'name': 'Superscript', 'title': 'Superscript', 'css': 'wym_tools_superscript'},
{'name': 'Subscript', 'title': 'Subscript', 'css': 'wym_tools_subscript'},
@@ -523,7 +523,7 @@ $(function(){
var editor = $.wymeditors(0);
var save = function ( callback ) {
show_modal( "Saving page", "progress" );
// Do save.
$.ajax( {
url: save_url,
@@ -531,7 +531,7 @@ $(function(){
data: {
id: page_id,
content: editor.xhtml(),
annotations: JSON.stringify(new Object()),
annotations: JSON.stringify(new Object()),
// annotations: JSON.stringify(annotations),
"_": "true"
},
@@ -568,16 +568,16 @@ $(function(){
window.document.location = page_list_url;
}
});
// Initialize galaxy elements.
//init_galaxy_elts(editor);
//
// Containers, Galaxy style
//
var containers_menu = $("<div class='galaxy-page-editor-button'><a id='insert-galaxy-link' class='action-button popup' href='#'>Paragraph type</a></div>");
$(".wym_area_top").append( containers_menu );
// Add menu options.
var items = {}
$.each( editor._options.containersItems, function( k, v ) {
@@ -585,58 +585,58 @@ $(function(){
items[ v.title.replace( '_', ' ' ) ] = function() { editor.container( tagname ) }
});
make_popupmenu( containers_menu, items);
//
// Create 'Insert Link to Galaxy Object' menu.
//
// Add menu button.
var insert_link_menu_button = $("<div><a id='insert-galaxy-link' class='action-button popup' href='#'>Insert Link to Galaxy Object</a></div>").addClass('galaxy-page-editor-button');
$(".wym_area_top").append(insert_link_menu_button);
// Add menu options.
make_popupmenu( insert_link_menu_button, {
"Insert History Link": function() {
editor.dialog(Galaxy.DIALOG_HISTORY_LINK);
editor.dialog(CONTROLS.DIALOG_HISTORY_LINK);
},
"Insert Dataset Link": function() {
editor.dialog(Galaxy.DIALOG_DATASET_LINK);
editor.dialog(CONTROLS.DIALOG_DATASET_LINK);
},
"Insert Workflow Link": function() {
editor.dialog(Galaxy.DIALOG_WORKFLOW_LINK);
editor.dialog(CONTROLS.DIALOG_WORKFLOW_LINK);
},
"Insert Page Link": function() {
editor.dialog(Galaxy.DIALOG_PAGE_LINK);
editor.dialog(CONTROLS.DIALOG_PAGE_LINK);
},
"Insert Visualization Link": function() {
editor.dialog(Galaxy.DIALOG_VISUALIZATION_LINK);
editor.dialog(CONTROLS.DIALOG_VISUALIZATION_LINK);
},
});
//
// Create 'Embed Galaxy Object' menu.
//
// Add menu button.
var embed_object_button = $("<div><a id='embed-galaxy-object' class='action-button popup' href='#'>Embed Galaxy Object</a></div>").addClass('galaxy-page-editor-button');
$(".wym_area_top").append(embed_object_button);
// Add menu options.
make_popupmenu( embed_object_button, {
"Embed History": function() {
editor.dialog(Galaxy.DIALOG_EMBED_HISTORY);
editor.dialog(CONTROLS.DIALOG_EMBED_HISTORY);
},
"Embed Dataset": function() {
editor.dialog(Galaxy.DIALOG_EMBED_DATASET);
editor.dialog(CONTROLS.DIALOG_EMBED_DATASET);
},
"Embed Workflow": function() {
editor.dialog(Galaxy.DIALOG_EMBED_WORKFLOW);
editor.dialog(CONTROLS.DIALOG_EMBED_WORKFLOW);
},
"Embed Visualization": function() {
editor.dialog(Galaxy.DIALOG_EMBED_VISUALIZATION);
editor.dialog(CONTROLS.DIALOG_EMBED_VISUALIZATION);
},
//"Embed Page": function() {
// editor.dialog(Galaxy.DIALOG_EMBED_PAGE);
// editor.dialog(CONTROLS.DIALOG_EMBED_PAGE);
//}
});
});
});
-287
View File
@@ -1,287 +0,0 @@
!function( exports, $ ){
"use strict"
var ensure_dd_helper = function () {
// Insert div that covers everything when dragging the borders
if ( $( "#dd-helper" ).length == 0 ) {
$( "<div id='dd-helper'/>" ).appendTo( "body" ).hide();
}
}
// Panels
var MIN_PANEL_WIDTH = 160,
MAX_PANEL_WIDTH = 800;
var Panel = function( options ) {
this.$panel = options.panel;
this.$center = options.center;
this.$drag = options.drag;
this.$toggle = options.toggle;
this.left = !options.right;
this.hidden = false;
this.hidden_by_tool = false;
this.saved_size = null;
this.init();
}
$.extend( Panel.prototype, {
resize: function( x ) {
this.$panel.css( "width", x );
if ( this.left ) {
this.$center.css( "left", x );
} else {
this.$center.css( "right", x );
}
// ie7-recalc.js
if ( document.recalc ) { document.recalc(); }
},
do_toggle: function() {
var self = this;
if ( this.hidden ) {
this.$toggle.removeClass( "hidden" );
if ( this.left ) {
this.$panel.css( "left", - this.saved_size ).show().animate( { "left": 0 }, "fast", function () {
self.resize( self.saved_size );
});
} else {
this.$panel.css( "right", - this.saved_size ).show().animate( { "right": 0 }, "fast", function () {
self.resize( self.saved_size );
});
}
self.hidden = false;
} else {
self.saved_size = this.$panel.width();
if ( document.recalc ) { document.recalc(); }
// Hide border
if ( this.left ) {
this.$panel.animate( { left: - this.saved_size }, "fast" );
} else {
this.$panel.animate( { right: - this.saved_size }, "fast" );
}
// self.resize(0);
if ( this.left ) {
this.$center.css( "left", 0 );
} else {
this.$center.css( "right", 0 );
}
self.hidden = true;
self.$toggle.addClass( "hidden" );
}
this.hidden_by_tool = false;
},
handle_minwidth_hint: function( x ) {
var space = this.$center.width() - ( this.hidden ? this.saved_size : 0 );
if ( space < x )
{
if ( ! this.hidden ) {
this.do_toggle();
this.hidden_by_tool = true;
}
} else {
if ( this.hidden_by_tool ) {
this.do_toggle();
this.hidden_by_tool = false;
}
}
},
force_panel: function( op ) {
if ( ( this.hidden && op == 'show' ) || ( ! this.hidden && op == 'hide' ) ) {
this.do_toggle();
}
},
init: function() {
var self = this,
prevX;
// Pull the collapse element out to body level so it is visible when panel is hidden
self.$toggle.remove().appendTo( "body" );
// Hide/show using toggle element
self.$toggle.on( "click", function() { self.do_toggle(); } );
// Resizing using drag element
function move( e ){
var delta = e.pageX - prevX;
prevX = e.pageX;
var oldWidth = self.$panel.width(),
newWidth = ( self.left )?( oldWidth + delta ):( oldWidth - delta );
// Limit range
newWidth = Math.min( MAX_PANEL_WIDTH, Math.max( MIN_PANEL_WIDTH, newWidth ) );
self.resize( newWidth );
}
this.$drag.on( "mousedown", function( e ) {
prevX = e.pageX;
$( '#dd-helper' ).show()
.on( 'mousemove', move )
.one( 'mouseup', function( e ){
$( this ).hide().off( 'mousemove', move );
});
});
window.force_left_panel = function( x ) { self.force_panel( x ) };
window.handle_minwidth_hint = function( x ) { self.handle_minwidth_hint( x ) };
}
});
// Modal dialog boxes
var Modal = function( options ) {
this.$overlay = options.overlay;
this.$dialog = options.dialog;
this.$header = this.$dialog.find( ".modal-header" );
this.$body = this.$dialog.find( ".modal-body" );
this.$footer = this.$dialog.find( ".modal-footer" );
this.$backdrop = options.backdrop;
// Close button
this.$header.find( ".close" ).on( "click", $.proxy( this.hide, this ) );
}
$.extend( Modal.prototype, {
setContent: function( options ) {
this.$header.hide();
// Title
if ( options.title ) {
this.$header.find( ".title" ).html( options.title );
this.$header.show();
}
if ( options.closeButton ) {
this.$header.find( ".close" ).show();
this.$header.show();
} else {
this.$header.find( ".close" ).hide();
}
// Buttons
this.$footer.hide();
var $buttons = this.$footer.find( ".buttons" ).html( "" );
if ( options.buttons ) {
$.each( options.buttons, function( name, value ) {
$buttons.append( $( '<button></button> ' ).text( name ).click( value ) ).append( " " );
});
this.$footer.show();
}
var $extraButtons = this.$footer.find( ".extra_buttons" ).html( "" );
if ( options.extra_buttons ) {
$.each( options.extra_buttons, function( name, value ) {
$extraButtons.append( $( '<button></button>' ).text( name ).click( value ) ).append( " " );
});
this.$footer.show();
}
// Body
var body = options.body;
if ( body == "progress" ) {
body = $("<div class='progress progress-striped active'><div class='progress-bar' style='width: 100%'></div></div>");
}
this.$body.html( body );
},
show: function( options, callback ) {
if ( ! this.$dialog.is( ":visible" ) ) {
if ( options.backdrop) {
this.$backdrop.addClass( "in" );
} else {
this.$backdrop.removeClass( "in" );
}
this.$overlay.show();
this.$dialog.show();
this.$overlay.addClass("in");
// Fix min-width so that modal cannot shrink considerably if new content is loaded.
this.$body.css( "min-width", this.$body.width() );
// Set max-height so that modal does not exceed window size and is in middle of page.
// TODO: this could perhaps be handled better using CSS.
this.$body.css( "max-height",
$(window).height() -
this.$footer.outerHeight() -
this.$header.outerHeight() -
parseInt( this.$dialog.css( "padding-top" ), 10 ) -
parseInt( this.$dialog.css( "padding-bottom" ), 10 )
);
}
// Callback on init
if ( callback ) {
callback();
}
},
hide: function() {
var modal = this;
modal.$dialog.fadeOut( function() {
modal.$overlay.hide();
modal.$backdrop.removeClass( "in" );
modal.$body.children().remove();
// Clear min-width to allow for modal to take size of new body.
modal.$body.css( "min-width", undefined );
});
}
});
var modal;
$(function(){
modal = new Modal( { overlay: $("#top-modal"), dialog: $("#top-modal-dialog"), backdrop: $("#top-modal-backdrop") } );
});
// Backward compatibility
function hide_modal() {
modal.hide();
}
function show_modal( title, body, buttons, extra_buttons, init_fn ) {
modal.setContent( { title: title, body: body, buttons: buttons, extra_buttons: extra_buttons } );
modal.show( { backdrop: true }, init_fn );
}
function show_message( title, body, buttons, extra_buttons, init_fn ) {
modal.setContent( { title: title, body: body, buttons: buttons, extra_buttons: extra_buttons } );
modal.show( { backdrop: false }, init_fn );
}
function show_in_overlay( options ) {
var width = options.width || '600';
var height = options.height || '400';
var scroll = options.scroll || 'auto';
$("#overlay-background").bind( "click.overlay", function() {
hide_modal();
$("#overlay-background").unbind( "click.overlay" );
});
modal.setContent( { closeButton: true, title: "&nbsp;", body: $( "<div style='margin: -5px;'><iframe style='margin: 0; padding: 0;' src='" + options.url + "' width='" + width + "' height='" + height + "' scrolling='" + scroll + "' frameborder='0'></iframe></div>" ) } );
modal.show( { backdrop: true } );
}
function user_changed( user_email, is_admin ) {
if ( user_email ) {
$(".loggedin-only").show();
$(".loggedout-only").hide();
$("#user-email").text( user_email );
if ( is_admin ) {
$(".admin-only").show();
}
} else {
$(".loggedin-only").hide();
$(".loggedout-only").show();
$(".admin-only").hide();
}
}
// Masthead dropdown menus
$(function() {
var $dropdowns = $("#masthead ul.nav > li.dropdown > .dropdown-menu");
$("body").on( "click.nav_popups", function( e ) {
$dropdowns.hide();
$("#dd-helper").hide();
// If the target is in the menu, treat normally
if ( $(e.target).closest( "#masthead ul.nav > li.dropdown > .dropdown-menu" ).length ) {
return;
}
// Otherwise, was the click in a tab
var $clicked = $(e.target).closest( "#masthead ul.nav > li.dropdown" );
if ( $clicked.length ) {
$("#dd-helper").show();
$clicked.children( ".dropdown-menu" ).show();
e.preventDefault();
}
});
});
// Exports
exports.ensure_dd_helper = ensure_dd_helper;
exports.Panel = Panel;
exports.Modal = Modal;
exports.hide_modal = hide_modal;
exports.show_modal = show_modal;
exports.show_message = show_message;
exports.show_in_overlay = show_in_overlay;
exports.user_changed = user_changed;
}( window, window.jQuery );
-158
View File
@@ -1,158 +0,0 @@
// dependencies
define([ "libs/underscore", "mvc/tools" ], function( _, Tools ) {
var checkUncheckAll = function( name, check ) {
$("input[name='" + name + "'][type='checkbox']").attr('checked', !!check);
}
$(".tool-share-link").each( function() {
var href = $(this).attr("href");
var href = $(this).attr("data-link");
$(this).click(function() {
window.prompt("Copy to clipboard: Ctrl+C, Enter", href);
});
});
// Inserts the Select All / Unselect All buttons for checkboxes
$("div.checkUncheckAllPlaceholder").each( function() {
var check_name = $(this).attr("checkbox_name");
select_link = $("<a class='action-button'></a>").text("Select All").click(function() {
checkUncheckAll(check_name, true);
});
unselect_link = $("<a class='action-button'></a>").text("Unselect All").click(function() {
checkUncheckAll(check_name, false);
});
$(this).append(select_link).append(" ").append(unselect_link);
});
var SELECTION_TYPE = {
'select_single': {
'icon_class': 'fa-file-o',
'select_by': 'Run tool on single input',
'allow_remap': true
},
'select_multiple': {
'icon_class': 'fa-files-o',
'select_by': 'Run tool in parallel across multiple datasets',
'allow_remap': false,
'min_option_count': 2 // Don't show multiple select switch if only
// one dataset available.
},
'select_collection': {
'icon_class': 'fa-folder-o',
'select_by': 'Run tool in parallel across dataset collection',
'allow_remap': false
},
'multiselect_single': {
'icon_class': 'fa-list-alt',
'select_by': 'Run tool over multiple datasets',
'allow_remap': true
},
'multiselect_collection': {
'icon_class': 'fa-folder-o',
'select_by': 'Run tool over dataset collection',
'allow_remap': false,
},
'select_single_collection': {
'icon_class': 'fa-file-o',
'select_by': 'Run tool on single collection',
'allow_remap': true
},
'select_map_over_collections': {
'icon_class': 'fa-folder-o',
'select_by': 'Map tool over compontents of nested collection',
'allow_remap': false,
}
};
var SwitchSelectView = Backbone.View.extend({
initialize: function( data ) {
var defaultOption = data.default_option;
var defaultIndex = null;
var switchOptions = data.switch_options;
this.switchOptions = switchOptions;
this.prefix = data.prefix;
var el = this.$el;
var view = this;
var index = 0;
var visibleCount = 0;
_.each( this.switchOptions, function( option, onValue ) {
var numValues = _.size( option.options );
var selectionType = SELECTION_TYPE[ onValue ];
var iIndex = index++;
var hidden = false;
if( defaultOption == onValue ) {
defaultIndex = iIndex;
} else if( numValues < ( selectionType.min_option_count || 1 ) ) {
hidden = true;
}
if( ! hidden ) {
visibleCount++;
var button = $('<i class="fa ' + selectionType['icon_class'] + ' runOptionIcon" style="padding-left: 5px; padding-right: 2px;"></i>').click(function() {
view.enableSelectBy( iIndex, onValue );
}).attr(
'title',
selectionType['select_by']
).data( "index", iIndex );
view.formRow().find( "label" ).append( button );
}
});
if( visibleCount < 2 ) {
// Don't show buttons to switch options...
view.formRow().find("i.runOptionIcon").hide();
}
if( defaultIndex != null) {
view.enableSelectBy( defaultIndex, defaultOption );
}
},
formRow: function() {
return this.$el.closest( ".form-row" );
},
render: function() {
},
enableSelectBy: function( enableIndex, onValue ) {
var selectionType = SELECTION_TYPE[onValue];
if(selectionType["allow_remap"]) {
$("div#remap-row").css("display", "inherit");
} else {
$("div#remap-row").css("display", "none");
}
this.formRow().find( "i" ).each(function(_, iElement) {
var $iElement = $(iElement);
var index = $iElement.data("index");
if(index == enableIndex) {
$iElement.css('color', 'black');
} else {
$iElement.css('color', 'Gray');
}
});
var $select = this.$( "select" );
var options = this.switchOptions[ onValue ];
$select.attr( "name", this.prefix + options.name );
$select.attr( "multiple", options.multiple );
// Replace options regardless.
var select2ed = this.$(".select2-container").length > 0;
$select.html(""); // clear out select list
_.each( options.options, function( option ) {
var text = option[0];
var value = option[1];
var selected = option[2];
$select.append($("<option />", {text: text, val: value, selected: selected}));
});
if( select2ed ) {
// Without this select2 does not update options.
$select.select2();
}
}
});
return {
SwitchSelectView: SwitchSelectView
};
});
+93
View File
@@ -0,0 +1,93 @@
define([
'utils/utils',
'layout/menu',
'layout/scratchbook',
'mvc/user/user-quotameter',
], function( Utils, Menu, Scratchbook, QuotaMeter ) {
/** Masthead **/
var View = Backbone.View.extend({
initialize : function( options ) {
var self = this;
this.options = options;
this.setElement( this._template() );
this.$navbarBrandLink = this.$( '.navbar-brand-link' );
this.$navbarBrandImage = this.$( '.navbar-brand-image' );
this.$navbarBrandTitle = this.$( '.navbar-brand-title' );
this.$navbarTabs = this.$( '.navbar-tabs' );
this.$quoteMeter = this.$( '.quota-meter-container' );
// build tabs
this.collection = new Menu.Collection();
this.collection.on( 'add', function( model ) {
self.$navbarTabs.append( new Menu.Tab( { model : model } ).render().$el );
}).on( 'reset', function() {
self.$navbarTabs.empty();
}).on( 'dispatch', function( callback ) {
self.collection.each( function ( m ) { callback( m ) });
}).fetch( this.options );
// scratchbook
Galaxy.frame = this.frame = new Scratchbook( { collection: this.collection } );
$( 'body' ).append( this.frame.$el );
// set up the quota meter (And fetch the current user data from trans)
// add quota meter to masthead
Galaxy.quotaMeter = this.quotaMeter = new QuotaMeter.UserQuotaMeter({
model : Galaxy.user,
el : this.$quoteMeter
});
// loop through beforeunload functions if the user attempts to unload the page
$( window ).on( 'click', function( e ) {
var $download_link = $( e.target ).closest( 'a[download]' );
if ( $download_link.length == 1 ) {
if( $( 'iframe[id=download]' ).length === 0 ) {
$( 'body' ).append( $( '<iframe/>' ).attr( 'id', 'download' ).hide() );
}
$( 'iframe[id=download]' ).attr( 'src', $download_link.attr( 'href' ) );
e.preventDefault();
}
}).on( 'beforeunload', function() {
var text = '';
self.collection.each( function( model ) {
var q = model.get( 'onbeforeunload' ) && model.get( 'onbeforeunload' )();
q && ( text += q + ' ' );
});
if ( text !== '' ) {
return text;
}
});
},
render: function() {
this.$navbarBrandTitle.html( 'Galaxy ' + ( this.options.brand && '/ ' + this.options.brand || '' ) );
this.$navbarBrandLink.attr( 'href', this.options.logo_url );
this.$navbarBrandImage.attr( 'src', this.options.logo_src );
this.quotaMeter.render();
return this;
},
/** body template */
_template: function() {
return '<div id="masthead" class="navbar navbar-fixed-top navbar-inverse">' +
'<div class="navbar-header">' +
'<div class="navbar-tabs"/>' +
'</div>' +
'<div class="navbar-brand">' +
'<a class="navbar-brand-link">' +
'<img class="navbar-brand-image"/>' +
'<span class="navbar-brand-title"/>' +
'</a>' +
'</div>' +
'<div class="quota-meter-container"/>' +
'<div class="navbar-icons"/>' +
'</div>';
}
});
return {
View: View
};
});
+386
View File
@@ -0,0 +1,386 @@
/** Masthead Collection **/
define(['mvc/tours'], function( Tours ) {
var Collection = Backbone.Collection.extend({
model: Backbone.Model.extend({
defaults: {
visible : true,
target : '_parent'
}
}),
fetch: function( options ){
options = options || {};
this.reset();
//
// Analyze data tab.
//
this.add({
id : 'analysis',
title : 'Analyze Data',
url : '',
tooltip : 'Analysis home view'
});
//
// Workflow tab.
//
this.add({
id : 'workflow',
title : 'Workflow',
url : 'workflow',
tooltip : 'Chain tools into workflows',
disabled : !Galaxy.user.id
});
//
// 'Shared Items' or Libraries tab.
//
this.add({
id : 'shared',
title : 'Shared Data',
url : 'library/index',
tooltip : 'Access published resources',
menu : [{
title : 'Data Libraries deprecated',
url : 'library/index'
},{
title : 'Data Libraries',
url : 'library/list',
divider : true
},{
title : 'Published Histories',
url : 'history/list_published'
},{
title : 'Published Workflows',
url : 'workflow/list_published'
},{
title : 'Published Visualizations',
url : 'visualization/list_published'
},{
title : 'Published Pages',
url : 'page/list_published'
}]
});
//
// Lab menu.
//
options.user_requests && this.add({
id : 'lab',
title : 'Lab',
menu : [{
title : 'Sequencing Requests',
url : 'requests/index'
},{
title : 'Find Samples',
url : 'requests/find_samples_index'
},{
title : 'Help',
url : options.lims_doc_url
}]
});
//
// Visualization tab.
//
this.add({
id : 'visualization',
title : 'Visualization',
url : 'visualization/list',
tooltip : 'Visualize datasets',
disabled : !Galaxy.user.id,
menu : [{
title : 'New Track Browser',
url : 'visualization/trackster',
target : '_frame'
},{
title : 'Saved Visualizations',
url : 'visualization/list',
target : '_frame'
}]
});
//
// Admin.
//
Galaxy.user.get( 'is_admin' ) && this.add({
id : 'admin',
title : 'Admin',
url : 'admin',
tooltip : 'Administer this Galaxy',
cls : 'admin-only'
});
//
// Help tab.
//
var helpTab = {
id : 'help',
title : 'Help',
tooltip : 'Support, contact, and community hubs',
menu : [{
title : 'Support',
url : options.support_url,
target : '_blank'
},{
title : 'Search',
url : options.search_url,
target : '_blank'
},{
title : 'Mailing Lists',
url : options.mailing_lists,
target : '_blank'
},{
title : 'Videos',
url : options.screencasts_url,
target : '_blank'
},{
title : 'Wiki',
url : options.wiki_url,
target : '_blank'
},{
title : 'How to Cite Galaxy',
url : options.citation_url,
target : '_blank'
},{
title : 'Interactive Tours',
onclick : function(){
if (Galaxy.app){
Galaxy.app.display(new Tours.ToursView());
} else {
// Redirect and use clientside routing to go to tour index
window.location = Galaxy.root + "#/tours";
}
},
target : 'galaxy_main'
}]
};
options.terms_url && helpTab.menu.push({
title : 'Terms and Conditions',
url : options.terms_url,
target : '_blank'
});
options.biostar_url && helpTab.menu.unshift({
title : 'Ask a question',
url : 'biostar/biostar_question_redirect',
target : '_blank'
});
options.biostar_url && helpTab.menu.unshift({
title : 'Galaxy Biostar',
url : options.biostar_url_redirect,
target : '_blank'
});
this.add( helpTab );
//
// User tab.
//
if ( !Galaxy.user.id ){
var userTab = {
id : 'user',
title : 'User',
cls : 'loggedout-only',
tooltip : 'Account registration or login',
menu : [{
title : 'Login',
url : 'user/login',
target : 'galaxy_main'
}]
};
options.allow_user_creation && userTab.menu.push({
title : 'Register',
url : 'user/create',
target : 'galaxy_main'
});
this.add( userTab );
} else {
var userTab = {
id : 'user',
title : 'User',
cls : 'loggedin-only',
tooltip : 'Account preferences and saved data',
menu : [{
title : 'Logged in as ' + Galaxy.user.get( 'email' )
},{
title : 'Preferences',
url : 'user?cntrller=user',
target : 'galaxy_main'
},{
title : 'Custom Builds',
url : 'user/dbkeys',
target : 'galaxy_main'
},{
title : 'Logout',
url : 'user/logout',
target : '_top',
divider : true
},{
title : 'Saved Histories',
url : 'history/list',
target : 'galaxy_main'
},{
title : 'Saved Datasets',
url : 'dataset/list',
target : 'galaxy_main'
},{
title : 'Saved Pages',
url : 'page/list',
target : '_top'
},{
title : 'API Keys',
url : 'user/api_keys?cntrller=user',
target : 'galaxy_main'
}]
};
options.use_remote_user && userTab.menu.push({
title : 'Public Name',
url : 'user/edit_username?cntrller=user',
target : 'galaxy_main'
});
this.add( userTab );
}
var activeView = this.get( options.active_view );
activeView && activeView.set( 'active', true );
return new jQuery.Deferred().resolve().promise();
}
});
/** Masthead tab **/
var Tab = Backbone.View.extend({
initialize: function ( options ) {
this.model = options.model;
this.setElement( this._template() );
this.$dropdown = this.$( '.dropdown' );
this.$toggle = this.$( '.dropdown-toggle' );
this.$menu = this.$( '.dropdown-menu' );
this.$note = this.$( '.dropdown-note' );
this.listenTo( this.model, 'change', this.render, this );
},
events: {
'click .dropdown-toggle' : '_toggleClick'
},
render: function() {
var self = this;
$( '.tooltip' ).remove();
this.$el.attr( 'id', this.model.id )
.css( { visibility : this.model.get( 'visible' ) && 'visible' || 'hidden' } );
this.model.set( 'url', this._formatUrl( this.model.get( 'url' ) ) );
this.$note.html( this.model.get( 'note' ) || '' )
.removeClass().addClass( 'dropdown-note' )
.addClass( this.model.get( 'note_cls' ) )
.css( { 'display' : this.model.get( 'show_note' ) && 'block' || 'none' } )
this.$toggle.html( this.model.get( 'title' ) || '' )
.removeClass().addClass( 'dropdown-toggle' )
.addClass( this.model.get( 'cls' ) )
.addClass( this.model.get( 'icon' ) && 'fa fa-2x ' + this.model.get( 'icon' ) )
.addClass( this.model.get( 'toggle' ) && 'toggle' )
.attr( 'target', this.model.get( 'target' ) )
.attr( 'href', this.model.get( 'url' ) )
.attr( 'title', this.model.get( 'tooltip' ) )
.tooltip( 'destroy' );
this.model.get( 'tooltip' ) && this.$toggle.tooltip( { placement: 'bottom' } );
this.$dropdown.removeClass().addClass( 'dropdown' )
.addClass( this.model.get( 'disabled' ) && 'disabled' )
.addClass( this.model.get( 'active' ) && 'active' );
if ( this.model.get( 'menu' ) && this.model.get( 'show_menu' ) ) {
this.$menu.show();
$( '#dd-helper' ).show().off().on( 'click', function() {
$( '#dd-helper' ).hide();
self.model.set( 'show_menu', false );
});
} else {
self.$menu.hide();
$( '#dd-helper' ).hide();
}
this.$menu.empty().removeClass( 'dropdown-menu' );
if ( this.model.get( 'menu' ) ) {
_.each( this.model.get( 'menu' ), function( menuItem ) {
self.$menu.append( self._buildMenuItem( menuItem ) );
menuItem.divider && self.$menu.append( $( '<li/>' ).addClass( 'divider' ) );
});
self.$menu.addClass( 'dropdown-menu' );
self.$toggle.append( $( '<b/>' ).addClass( 'caret' ) );
}
return this;
},
/** Add new menu item */
_buildMenuItem: function ( options ) {
var self = this;
options = _.defaults( options || {}, {
title : '',
url : '',
target : '_parent'
});
options.url = self._formatUrl( options.url );
return $( '<li/>' ).append(
$( '<a/>' ).attr( 'href', options.url )
.attr( 'target', options.target )
.html( options.title )
.on( 'click', function( e ) {
e.preventDefault();
self.model.set( 'show_menu', false );
if (options.onclick){
options.onclick();
} else {
Galaxy.frame.add( options );
}
})
);
},
/** Handle click event */
_toggleClick: function( e ) {
var self = this;
var model = this.model;
e.preventDefault();
$( '.tooltip' ).hide();
model.trigger( 'dispatch', function( m ) {
model.id !== m.id && m.get( 'menu' ) && m.set( 'show_menu', false );
});
if ( !model.get( 'disabled' ) ) {
if ( !model.get( 'menu' ) ) {
model.get( 'onclick' ) ? model.get( 'onclick' )() : Galaxy.frame.add( model.attributes );
} else {
model.set( 'show_menu', true );
}
} else {
function buildLink( label, url ) {
return $( '<div/>' ).append( $( '<a/>' ).attr( 'href', Galaxy.root + url ).html( label ) ).html()
}
this.$toggle.popover && this.$toggle.popover( 'destroy' );
this.$toggle.popover({
html : true,
placement : 'bottom',
content : 'Please ' + buildLink( 'login', 'user/login?use_panels=True' ) + ' or ' +
buildLink( 'register', 'user/create?use_panels=True' ) + ' to use this feature.'
}).popover( 'show' );
setTimeout( function() { self.$toggle.popover( 'destroy' ) }, 5000 );
}
},
/** Url formatting */
_formatUrl: function( url ) {
return typeof url == 'string' && url.indexOf( '//' ) === -1 && url.charAt( 0 ) != '/' ? Galaxy.root + url : url;
},
/** body tempate */
_template: function () {
return '<ul class="nav navbar-nav">' +
'<li class="dropdown">' +
'<a class="dropdown-toggle"/>' +
'<ul class="dropdown-menu"/>' +
'<div class="dropdown-note"/>' +
'</li>' +
'</ul>';
}
});
return {
Collection : Collection,
Tab : Tab
};
});
+150
View File
@@ -0,0 +1,150 @@
define([
'jquery',
], function (jQuery){
"use strict";
// ============================================================================
//TODO: (the older version) unify with ui-modal (the newer version)
var $ = jQuery;
// Modal dialog boxes
var Modal = function( options ) {
this.$overlay = options.overlay;
this.$dialog = options.dialog;
this.$header = this.$dialog.find( ".modal-header" );
this.$body = this.$dialog.find( ".modal-body" );
this.$footer = this.$dialog.find( ".modal-footer" );
this.$backdrop = options.backdrop;
// Close button
this.$header.find( ".close" ).on( "click", $.proxy( this.hide, this ) );
};
$.extend( Modal.prototype, {
setContent: function( options ) {
this.$header.hide();
// Title
if ( options.title ) {
this.$header.find( ".title" ).html( options.title );
this.$header.show();
}
if ( options.closeButton ) {
this.$header.find( ".close" ).show();
this.$header.show();
} else {
this.$header.find( ".close" ).hide();
}
// Buttons
this.$footer.hide();
var $buttons = this.$footer.find( ".buttons" ).html( "" );
if ( options.buttons ) {
$.each( options.buttons, function( name, value ) {
$buttons.append( $( '<button></button> ' ).text( name ).click( value ) ).append( " " );
});
this.$footer.show();
}
var $extraButtons = this.$footer.find( ".extra_buttons" ).html( "" );
if ( options.extra_buttons ) {
$.each( options.extra_buttons, function( name, value ) {
$extraButtons.append( $( '<button></button>' ).text( name ).click( value ) ).append( " " );
});
this.$footer.show();
}
// Body
var body = options.body;
if ( body == "progress" ) {
body = $("<div class='progress progress-striped active'><div class='progress-bar' style='width: 100%'></div></div>");
}
this.$body.html( body );
},
show: function( options, callback ) {
if ( ! this.$dialog.is( ":visible" ) ) {
if ( options.backdrop) {
this.$backdrop.addClass( "in" );
} else {
this.$backdrop.removeClass( "in" );
}
this.$overlay.show();
this.$dialog.show();
this.$overlay.addClass("in");
// Fix min-width so that modal cannot shrink considerably if new content is loaded.
this.$body.css( "min-width", this.$body.width() );
// Set max-height so that modal does not exceed window size and is in middle of page.
// TODO: this could perhaps be handled better using CSS.
this.$body.css( "max-height",
$(window).height() -
this.$footer.outerHeight() -
this.$header.outerHeight() -
parseInt( this.$dialog.css( "padding-top" ), 10 ) -
parseInt( this.$dialog.css( "padding-bottom" ), 10 )
);
}
// Callback on init
if ( callback ) {
callback();
}
},
hide: function() {
var modal = this;
modal.$dialog.fadeOut( function() {
modal.$overlay.hide();
modal.$backdrop.removeClass( "in" );
modal.$body.children().remove();
// Clear min-width to allow for modal to take size of new body.
modal.$body.css( "min-width", undefined );
});
}
});
var modal;
$(function(){
modal = new Modal( { overlay: $("#top-modal"), dialog: $("#top-modal-dialog"), backdrop: $("#top-modal-backdrop") } );
});
// Backward compatibility
function hide_modal() {
modal.hide();
}
function show_modal( title, body, buttons, extra_buttons, init_fn ) {
modal.setContent( { title: title, body: body, buttons: buttons, extra_buttons: extra_buttons } );
modal.show( { backdrop: true }, init_fn );
}
function show_message( title, body, buttons, extra_buttons, init_fn ) {
modal.setContent( { title: title, body: body, buttons: buttons, extra_buttons: extra_buttons } );
modal.show( { backdrop: false }, init_fn );
}
function show_in_overlay( options ) {
var width = options.width || '600';
var height = options.height || '400';
var scroll = options.scroll || 'auto';
$("#overlay-background").bind( "click.overlay", function() {
hide_modal();
$("#overlay-background").unbind( "click.overlay" );
});
modal.setContent({
closeButton: true,
title: "&nbsp;",
body: $(
"<div style='margin: -5px;'><iframe style='margin: 0; padding: 0;' src='" + options.url +
"' width='" + width +
"' height='" + height +
"' scrolling='" + scroll +
"' frameborder='0'></iframe></div>"
)
});
modal.show( { backdrop: true } );
}
// ============================================================================
return {
Modal : Modal,
hide_modal : hide_modal,
show_modal : show_modal,
show_message : show_message,
show_in_overlay : show_in_overlay,
};
});
+136
View File
@@ -0,0 +1,136 @@
define([
'layout/masthead',
'layout/panel',
'mvc/ui/ui-modal',
'mvc/base-mvc'
], function( Masthead, Panel, Modal, BaseMVC ) {
// ============================================================================
var PageLayoutView = Backbone.View.extend( BaseMVC.LoggableMixin ).extend({
_logNamespace : 'layout',
el : 'body',
className : 'full-content',
_panelIds : [
'left', 'center', 'right'
],
defaultOptions : {
message_box_visible : false,
message_box_content : '',
message_box_class : 'info',
show_inactivity_warning : false,
inactivity_box_content : ''
},
initialize : function( options ) {
// TODO: remove globals
this.log( this + '.initialize:', options );
_.extend( this, _.pick( options, this._panelIds ) );
this.options = _.defaults( _.omit( options, this._panelIds ), this.defaultOptions );
Galaxy.modal = this.modal = new Modal.View();
this.masthead = new Masthead.View( this.options.config );
this.$el.attr( 'scroll', 'no' );
this.$el.append( this._template() );
this.$el.append( this.masthead.$el );
this.$el.append( this.modal.$el );
this.$messagebox = this.$( '#messagebox' );
this.$inactivebox = this.$( '#inactivebox' );
},
render : function() {
// TODO: Remove this line after select2 update
$( '.select2-hidden-accessible' ).remove();
this.log( this + '.render:' );
this.masthead.render();
this.renderMessageBox();
this.renderInactivityBox();
this.renderPanels();
return this;
},
/** Render message box */
renderMessageBox : function() {
if ( this.options.message_box_visible ){
var content = this.options.message_box_content || '';
var level = this.options.message_box_class || 'info';
this.$el.addClass( 'has-message-box' );
this.$messagebox
.attr( 'class', 'panel-' + level + '-message' )
.html( content )
.toggle( !!content )
.show();
} else {
this.$el.removeClass( 'has-message-box' );
this.$messagebox.hide();
}
return this;
},
/** Render inactivity warning */
renderInactivityBox : function() {
if( this.options.show_inactivity_warning ){
var content = this.options.inactivity_box_content || '';
var verificationLink = $( '<a/>' ).attr( 'href', Galaxy.root + 'user/resend_verification' ).html( 'Resend verification.' );
this.$el.addClass( 'has-inactivity-box' );
this.$inactivebox
.html( content )
.append( ' ' + verificationLink )
.toggle( !!content )
.show();
} else {
this.$el.removeClass( 'has-inactivity-box' );
this.$inactivebox.hide();
}
return this;
},
/** Render panels */
renderPanels : function() {
var page = this;
this._panelIds.forEach( function( panelId ){
if( _.has( page, panelId ) ){
page[ panelId ].setElement( '#' + panelId );
page[ panelId ].render();
} else if ( panelId !== 'center' ) {
page.center.$el.css( panelId, 0 );
}
});
return this;
},
/** body template */
_template: function() {
return [
'<div id="everything">',
'<div id="background"/>',
'<div id="messagebox"/>',
'<div id="inactivebox" class="panel-warning-message"/>',
'<div id="left"/>',
'<div id="center" class="inbound"/>',
'<div id="right"/>',
'</div>',
'<div id="dd-helper"/>',
'<noscript>',
'<div class="overlay overlay-background noscript-overlay">',
'<div>',
'<h3 class="title">Javascript Required for Galaxy</h3>',
'<div>',
'The Galaxy analysis interface requires a browser with Javascript enabled.<br>',
'Please enable Javascript and refresh this page',
'</div>',
'</div>',
'</div>',
'</noscript>'
].join('');
},
toString : function() { return 'PageLayoutView' }
});
// ============================================================================
return {
PageLayoutView: PageLayoutView
};
});
+294
View File
@@ -0,0 +1,294 @@
define([
'jquery',
'libs/underscore',
'libs/backbone',
'mvc/base-mvc',
], function( jQuery, _, Backbone, BASE_MVC ){
"use strict";
// ============================================================================
var $ = jQuery;
var MIN_PANEL_WIDTH = 160,
MAX_PANEL_WIDTH = 800;
// ----------------------------------------------------------------------------
/**
*
*/
var SidePanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend({
_logNamespace : 'layout',
initialize: function( attributes ){
this.log( this + '.initialize:', attributes );
this.title = attributes.title || this.title || '';
this.hidden = false;
this.savedSize = null;
this.hiddenByTool = false;
},
$center : function(){
return this.$el.siblings( '#center' );
},
$toggleButton : function(){
return this.$( '.unified-panel-footer > .panel-collapse' );
},
render: function(){
this.log( this + '.render:' );
this.$el.html( this.template( this.id ) );
},
/** panel dom template. id is 'right' or 'left' */
template: function(){
return [
this._templateHeader(),
this._templateBody(),
this._templateFooter(),
].join('');
},
/** panel dom template. id is 'right' or 'left' */
_templateHeader: function( data ){
return [
'<div class="unified-panel-header" unselectable="on">',
'<div class="unified-panel-header-inner">',
'<div class="panel-header-buttons" style="float: right"/>',
'<div class="panel-header-text">', _.escape( this.title ), '</div>',
'</div>',
'</div>',
].join('');
},
/** panel dom template. id is 'right' or 'left' */
_templateBody: function( data ){
return '<div class="unified-panel-body"/>';
},
/** panel dom template. id is 'right' or 'left' */
_templateFooter: function( data ){
return [
'<div class="unified-panel-footer">',
'<div class="panel-collapse ', _.escape( this.id ), '"/>',
'<div class="drag"/>',
'</div>',
].join('');
},
// ..............................................................
events : {
'mousedown .unified-panel-footer > .drag' : '_mousedownDragHandler',
'click .unified-panel-footer > .panel-collapse' : 'toggle'
},
_mousedownDragHandler : function( ev ){
var self = this,
draggingLeft = this.id === 'left',
prevX = ev.pageX;
function move( e ){
var delta = e.pageX - prevX;
prevX = e.pageX;
var oldWidth = self.$el.width(),
newWidth = draggingLeft?( oldWidth + delta ):( oldWidth - delta );
// Limit range
newWidth = Math.min( MAX_PANEL_WIDTH, Math.max( MIN_PANEL_WIDTH, newWidth ) );
self.resize( newWidth );
}
// this is a page wide overlay that assists in capturing the move and release of the mouse
// if not provided, progress and end wouldn't fire if the mouse moved out of the drag button area
$( '#dd-helper' )
.show()
.on( 'mousemove', move )
.one( 'mouseup', function( e ){
$( this ).hide().off( 'mousemove', move );
});
},
//TODO: the following three could be simplified I think
resize : function( newSize ){
this.$el.css( 'width', newSize );
// if panel is 'right' (this.id), move center right newSize number of pixels
this.$center().css( this.id, newSize );
return self;
},
show : function(){
if( !this.hidden ){ return; }
var self = this,
animation = {},
whichSide = this.id;
animation[ whichSide ] = 0;
self.$el
.css( whichSide, -this.savedSize )
.show()
.animate( animation, "fast", function(){
self.resize( self.savedSize );
});
self.hidden = false;
self.$toggleButton().removeClass( "hidden" );
return self;
},
hide : function(){
if( this.hidden ){ return; }
var self = this,
animation = {},
whichSide = this.id;
self.savedSize = this.$el.width();
animation[ whichSide ] = -this.savedSize;
this.$el.animate( animation, "fast" );
this.$center().css( whichSide, 0 );
self.hidden = true;
self.$toggleButton().addClass( "hidden" );
return self;
},
toggle: function( ev ){
var self = this;
if( self.hidden ){
self.show();
} else {
self.hide();
}
self.hiddenByTool = false;
return self;
},
// ..............................................................
//TODO: only used in message.mako?
/** */
handle_minwidth_hint: function( hint ){
var space = this.$center().width() - ( this.hidden ? this.savedSize : 0 );
if( space < hint ){
if( !this.hidden ){
this.toggle();
this.hiddenByTool = true;
}
} else {
if( this.hiddenByTool ){
this.toggle();
this.hiddenByTool = false;
}
}
return self;
},
/** */
force_panel : function( op ){
if( op == 'show' ){ return this.show(); }
if( op == 'hide' ){ return this.hide(); }
return self;
},
toString : function(){ return 'SidePanel(' + this.id + ')'; }
});
// ----------------------------------------------------------------------------
// TODO: side should be defined by page - not here
var LeftPanel = SidePanel.extend({
id : 'left',
});
var RightPanel = SidePanel.extend({
id : 'right',
});
// ----------------------------------------------------------------------------
/**
*
*/
var CenterPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend({
_logNamespace : 'layout',
initialize : function( options ){
this.log( this + '.initialize:', options );
/** previous view contained in the center panel - cached for removal later */
this.prev = null;
},
render : function(){
this.log( this + '.render:' );
this.$el.html( this.template() );
// ?: doesn't work/listen in events map
this.$( '#galaxy_main' ).on( 'load', _.bind( this._iframeChangeHandler, this ) );
},
/** */
_iframeChangeHandler : function( ev ){
var iframe = ev.currentTarget;
var location = iframe.contentWindow && iframe.contentWindow.location;
if( location && location.host ){
// show the iframe and hide MVCview div, remove any views in the MVCview div
$( iframe ).show();
if( this.prev ){
this.prev.remove();
}
this.$( '#center-panel' ).hide();
// TODO: move to Galaxy
Galaxy.trigger( 'galaxy_main:load', {
fullpath: location.pathname + location.search + location.hash,
pathname: location.pathname,
search : location.search,
hash : location.hash
});
this.trigger( 'galaxy_main:load', location );
}
},
/** */
display: function( view ){
// we need to display an MVC view: hide the iframe and show the other center panel
// first checking for any onbeforeunload handlers on the iframe
var contentWindow = this.$( '#galaxy_main' )[ 0 ].contentWindow || {};
var message = contentWindow.onbeforeunload && contentWindow.onbeforeunload();
if ( !message || confirm( message ) ) {
contentWindow.onbeforeunload = undefined;
// remove any previous views
if( this.prev ){
this.prev.remove();
}
this.prev = view;
this.$( '#galaxy_main' ).attr( 'src', 'about:blank' ).hide();
this.$( '#center-panel' ).scrollTop( 0 ).append( view.$el ).show();
this.trigger( 'center-panel:load', view );
} else {
if( view ){
view.remove();
}
}
},
template: function(){
return [
//TODO: remove inline styling
'<div style="position: absolute; width: 100%; height: 100%">',
'<iframe name="galaxy_main" id="galaxy_main" frameborder="0" ',
'style="position: absolute; width: 100%; height: 100%;"/>',
'<div id="center-panel" ',
'style="display: none; position: absolute; width: 100%; height: 100%; padding: 10px; overflow: auto;"/>',
'</div>'
].join('');
},
toString : function(){ return 'CenterPanel'; }
});
// ============================================================================
return {
LeftPanel : LeftPanel,
RightPanel : RightPanel,
CenterPanel : CenterPanel
};
});
+159
View File
@@ -0,0 +1,159 @@
/** Frame manager uses the ui-frames to create the scratch book masthead icon and functionality **/
define([ 'mvc/ui/ui-frames' ], function( Frames ) {
return Backbone.View.extend({
initialize : function( options ) {
var self = this;
options = options || {};
this.frames = new Frames.View({ visible : false });
this.setElement( this.frames.$el );
this.buttonActive = options.collection.add({
id : 'enable-scratchbook',
icon : 'fa-th',
tooltip : 'Enable/Disable Scratchbook',
onclick : function() {
self.active = !self.active;
self.buttonActive.set({
toggle : self.active,
show_note : self.active,
note_cls : self.active && 'fa fa-check'
});
!self.active && self.frames.hide();
},
onbeforeunload : function() {
if ( self.frames.length() > 0 ) {
return 'You opened ' + self.frames.length() + ' frame(s) which will be lost.';
}
}
});
this.buttonLoad = options.collection.add({
id : 'show-scratchbook',
icon : 'fa-eye',
tooltip : 'Show/Hide Scratchbook',
show_note : true,
visible : false,
onclick : function( e ) {
self.frames.visible ? self.frames.hide() : self.frames.show();
}
});
this.frames.on( 'add remove', function() {
this.visible && this.length() == 0 && this.hide();
self.buttonLoad.set( { 'note': this.length(), 'visible': this.length() > 0 } );
}).on( 'show hide ', function() {
self.buttonLoad.set( { 'toggle': this.visible, 'icon': this.visible && 'fa-eye' || 'fa-eye-slash' } );
});
},
/** Add a dataset to the frames */
addDataset: function( dataset_id ) {
var self = this;
require([ 'mvc/dataset/data' ], function( DATA ) {
var dataset = new DATA.Dataset( { id : dataset_id } );
$.when( dataset.fetch() ).then( function() {
// Construct frame config based on dataset's type.
var frame_config = {
title: dataset.get('name')
},
// HACK: For now, assume 'tabular' and 'interval' are the only
// modules that contain tabular files. This needs to be replaced
// will a is_datatype() function.
is_tabular = _.find( [ 'tabular', 'interval' ] , function( data_type ) {
return dataset.get( 'data_type' ).indexOf( data_type ) !== -1;
});
// Use tabular chunked display if dataset is tabular; otherwise load via URL.
if ( is_tabular ) {
var tabular_dataset = new DATA.TabularDataset( dataset.toJSON() );
_.extend( frame_config, {
content: function( parent_elt ) {
DATA.createTabularDatasetChunkedView({
model : tabular_dataset,
parent_elt : parent_elt,
embedded : true,
height : '100%'
});
}
});
}
else {
_.extend( frame_config, {
url: Galaxy.root + 'datasets/' + dataset.id + '/display/?preview=True'
});
}
self.add( frame_config );
});
});
},
/** Add a trackster visualization to the frames. */
addTrackster: function(viz_id) {
var self = this;
require(['viz/visualization', 'viz/trackster'], function(visualization, trackster) {
var viz = new visualization.Visualization({id: viz_id});
$.when( viz.fetch() ).then( function() {
var ui = new trackster.TracksterUI(Galaxy.root);
// Construct frame config based on dataset's type.
var frame_config = {
title: viz.get('name'),
type: 'other',
content: function(parent_elt) {
// Create view config.
var view_config = {
container: parent_elt,
name: viz.get('title'),
id: viz.id,
// FIXME: this will not work with custom builds b/c the dbkey needed to be encoded.
dbkey: viz.get('dbkey'),
stand_alone: false
},
latest_revision = viz.get('latest_revision'),
drawables = latest_revision.config.view.drawables;
// Set up datasets in drawables.
_.each(drawables, function(d) {
d.dataset = {
hda_ldda: d.hda_ldda,
id: d.dataset_id
};
});
view = ui.create_visualization(view_config,
latest_revision.config.viewport,
latest_revision.config.view.drawables,
latest_revision.config.bookmarks,
false);
}
};
self.add(frame_config);
});
});
},
/** Add and display a new frame/window based on options. */
add: function( options ) {
if ( options.target == '_blank' ) {
window.open( options.url );
} else if ( options.target == '_top' || options.target == '_parent' || options.target == '_self' ) {
window.location = options.url;
} else if ( !this.active ) {
var $galaxy_main = $( window.parent.document ).find( '#galaxy_main' );
if ( options.target == 'galaxy_main' || options.target == 'center' ){
if ( $galaxy_main.length === 0 ){
var href = options.url;
if ( href.indexOf( '?' ) == -1 )
href += '?';
else
href += '&';
href += 'use_panels=True';
window.location = href;
} else {
$galaxy_main.attr( 'src', options.url );
}
} else
window.location = options.url;
} else {
this.frames.add( options );
}
}
});
});
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 B

File diff suppressed because it is too large Load Diff
-166
View File
@@ -1,166 +0,0 @@
// =========================================================================
// ie7-recalc.js
// =========================================================================
(function() {
/* ---------------------------------------------------------------------
This allows refreshing of IE7 style rules. If you modify the DOM
you can update IE7 by calling document.recalc().
This should be the LAST module included.
--------------------------------------------------------------------- */
if (!IE7.loaded) return;
// remove all IE7 classes from an element
CLASSES = /\sie7_class\d+/g;
IE7.CSS.extend({
// store for elements that have style properties calculated
elements: {},
handlers: [],
// clear IE7 classes and styles
reset: function() {
this.removeEventHandlers();
// reset IE7 classes here
var elements = this.elements;
for (var i in elements) elements[i].runtimeStyle.cssText = "";
this.elements = {};
// reset runtimeStyle here
var elements = IE7.Rule.elements;
for (var i in elements) {
with (elements[i]) className = className.replace(CLASSES, "");
}
IE7.Rule.elements = {};
},
reload: function() {
this.rules = [];
this.getInlineStyles();
this.screen.load();
if (this.print) this.print.load();
this.refresh();
this.trash();
},
addRecalc: function(propertyName, test, handler, replacement) {
// call the ancestor method to add a wrapped recalc method
this.base(propertyName, test, function(element) {
// execute the original recalc method
handler(element);
// store a reference to this element so we can clear its style later
IE7.CSS.elements[element.uniqueID] = element;
}, replacement);
},
recalc: function() {
// clear IE7 styles and classes
this.reset();
// execute the ancestor method to perform recalculations
this.base();
},
addEventHandler: function(element, type, handler) {
element.attachEvent(type, handler);
// store the handler so it can be detached later
this.handlers.push(arguments);
},
removeEventHandlers: function() {
var handler;
while (handler = this.handlers.pop()) {
handler[0].detachEvent(handler[1], handler[2]);
}
},
getInlineStyles: function() {
// load inline styles
var styleSheets = document.getElementsByTagName("style"), styleSheet;
for (var i = styleSheets.length - 1; (styleSheet = styleSheets[i]); i--) {
if (!styleSheet.disabled && !styleSheet.ie7) {
var cssText = styleSheet.cssText || styleSheet.innerHTML;
this.styles.push(cssText);
styleSheet.cssText = cssText;
}
}
},
trash: function() {
// trash the old style sheets
var styleSheets = document.styleSheets, styleSheet, i;
for (i = 0; i < styleSheets.length; i++) {
styleSheet = styleSheets[i];
if (!styleSheet.ie7 && !styleSheet.cssText) {
styleSheet.cssText = styleSheet.cssText;
}
}
this.base();
},
getText: function(styleSheet) {
return styleSheet.cssText || this.base(styleSheet);
}
});
// remove event handlers (they eat memory)
IE7.CSS.addEventHandler(window, "onunload", function() {
IE7.CSS.removeEventHandlers();
});
// store all elements with an IE7 class assigned
IE7.Rule.elements = {};
IE7.Rule.prototype.extend({
add: function(element) {
// execute the ancestor "add" method
this.base(element);
// store a reference to this element so we can clear its classes later
IE7.Rule.elements[element.uniqueID] = element;
}
});
// store created pseudo elements
if (IE7.PseudoElement) {
IE7.PseudoElement.hash = {};
IE7.PseudoElement.prototype.extend({
create: function(target) {
var key = this.selector + ":" + target.uniqueID;
if (!IE7.PseudoElement.hash[key]) {
IE7.PseudoElement.hash[key] = true;
this.base(target);
}
}
});
}
IE7.HTML.extend({
elements: {},
addRecalc: function(selector, handler) {
// call the ancestor method to add a wrapped recalc method
this.base(selector, function(element) {
if (!this.elements[element.uniqueID]) {
// execute the original recalc method
handler(element);
// store a reference to this element so that
// it is not "fixed" again
this.elements[element.uniqueID] = element;
}
});
}
});
// allow refreshing of IE7 fixes
document.recalc = function(reload) {
if (IE7.CSS.screen) {
if (reload) IE7.CSS.reload();
IE7.recalc();
}
};
})();
+802
View File
@@ -0,0 +1,802 @@
/* ========================================================================
* bootstrap-tour - v0.10.1
* http://bootstraptour.com
* ========================================================================
* Copyright 2012-2013 Ulrich Sossou
*
* ========================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================================
*/
(function($, window) {
var Tour, document;
document = window.document;
Tour = (function() {
function Tour(options) {
var storage;
try {
storage = window.localStorage;
} catch (_error) {
storage = false;
}
this._options = $.extend({
name: 'tour',
steps: [],
container: 'body',
autoscroll: true,
keyboard: true,
storage: storage,
debug: false,
backdrop: false,
backdropPadding: 0,
redirect: true,
orphan: false,
duration: false,
delay: false,
basePath: '',
template: '<div class="popover" role="tooltip"> <div class="arrow"></div> <h3 class="popover-title"></h3> <div class="popover-content"></div> <div class="popover-navigation"> <div class="btn-group"> <button class="btn btn-sm btn-default" data-role="prev">&laquo; Prev</button> <button class="btn btn-sm btn-default" data-role="next">Next &raquo;</button> <button class="btn btn-sm btn-default" data-role="pause-resume" data-pause-text="Pause" data-resume-text="Resume">Pause</button> </div> <button class="btn btn-sm btn-default" data-role="end">End tour</button> </div> </div>',
afterSetState: function(key, value) {},
afterGetState: function(key, value) {},
afterRemoveState: function(key) {},
onStart: function(tour) {},
onEnd: function(tour) {},
onShow: function(tour) {},
onShown: function(tour) {},
onHide: function(tour) {},
onHidden: function(tour) {},
onNext: function(tour) {},
onPrev: function(tour) {},
onPause: function(tour, duration) {},
onResume: function(tour, duration) {}
}, options);
this._force = false;
this._inited = false;
this.backdrop = {
overlay: null,
$element: null,
$background: null,
backgroundShown: false,
overlayElementShown: false
};
this;
}
Tour.prototype.addSteps = function(steps) {
var step, _i, _len;
for (_i = 0, _len = steps.length; _i < _len; _i++) {
step = steps[_i];
this.addStep(step);
}
return this;
};
Tour.prototype.addStep = function(step) {
this._options.steps.push(step);
return this;
};
Tour.prototype.getStep = function(i) {
if (this._options.steps[i] != null) {
return $.extend({
id: "step-" + i,
path: '',
placement: 'right',
title: '',
content: '<p></p>',
next: i === this._options.steps.length - 1 ? -1 : i + 1,
prev: i - 1,
animation: true,
container: this._options.container,
autoscroll: this._options.autoscroll,
backdrop: this._options.backdrop,
backdropPadding: this._options.backdropPadding,
redirect: this._options.redirect,
orphan: this._options.orphan,
duration: this._options.duration,
delay: this._options.delay,
template: this._options.template,
onShow: this._options.onShow,
onShown: this._options.onShown,
onHide: this._options.onHide,
onHidden: this._options.onHidden,
onNext: this._options.onNext,
onPrev: this._options.onPrev,
onPause: this._options.onPause,
onResume: this._options.onResume
}, this._options.steps[i]);
}
};
Tour.prototype.init = function(force) {
this._force = force;
if (this.ended()) {
this._debug('Tour ended, init prevented.');
return this;
}
this.setCurrentStep();
this._initMouseNavigation();
this._initKeyboardNavigation();
this._onResize((function(_this) {
return function() {
return _this.showStep(_this._current);
};
})(this));
if (this._current !== null) {
this.showStep(this._current);
}
this._inited = true;
return this;
};
Tour.prototype.start = function(force) {
var promise;
if (force == null) {
force = false;
}
if (!this._inited) {
this.init(force);
}
if (this._current === null) {
promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
this._callOnPromiseDone(promise, this.showStep, 0);
}
return this;
};
Tour.prototype.next = function() {
var promise;
promise = this.hideStep(this._current);
return this._callOnPromiseDone(promise, this._showNextStep);
};
Tour.prototype.prev = function() {
var promise;
promise = this.hideStep(this._current);
return this._callOnPromiseDone(promise, this._showPrevStep);
};
Tour.prototype.goTo = function(i) {
var promise;
promise = this.hideStep(this._current);
return this._callOnPromiseDone(promise, this.showStep, i);
};
Tour.prototype.end = function() {
var endHelper, promise;
endHelper = (function(_this) {
return function(e) {
$(document).off("click.tour-" + _this._options.name);
$(document).off("keyup.tour-" + _this._options.name);
$(window).off("resize.tour-" + _this._options.name);
_this._setState('end', 'yes');
_this._inited = false;
_this._force = false;
_this._clearTimer();
if (_this._options.onEnd != null) {
return _this._options.onEnd(_this);
}
};
})(this);
promise = this.hideStep(this._current);
return this._callOnPromiseDone(promise, endHelper);
};
Tour.prototype.ended = function() {
return !this._force && !!this._getState('end');
};
Tour.prototype.restart = function() {
this._removeState('current_step');
this._removeState('end');
return this.start();
};
Tour.prototype.pause = function() {
var step;
step = this.getStep(this._current);
if (!(step && step.duration)) {
return this;
}
this._paused = true;
this._duration -= new Date().getTime() - this._start;
window.clearTimeout(this._timer);
this._debug("Paused/Stopped step " + (this._current + 1) + " timer (" + this._duration + " remaining).");
if (step.onPause != null) {
return step.onPause(this, this._duration);
}
};
Tour.prototype.resume = function() {
var step;
step = this.getStep(this._current);
if (!(step && step.duration)) {
return this;
}
this._paused = false;
this._start = new Date().getTime();
this._duration = this._duration || step.duration;
this._timer = window.setTimeout((function(_this) {
return function() {
if (_this._isLast()) {
return _this.next();
} else {
return _this.end();
}
};
})(this), this._duration);
this._debug("Started step " + (this._current + 1) + " timer with duration " + this._duration);
if ((step.onResume != null) && this._duration !== step.duration) {
return step.onResume(this, this._duration);
}
};
Tour.prototype.hideStep = function(i) {
var hideStepHelper, promise, step;
step = this.getStep(i);
if (!step) {
return;
}
this._clearTimer();
promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0);
hideStepHelper = (function(_this) {
return function(e) {
var $element;
$element = $(step.element);
if (!($element.data('bs.popover') || $element.data('popover'))) {
$element = $('body');
}
$element.popover('destroy').removeClass("tour-" + _this._options.name + "-element tour-" + _this._options.name + "-" + i + "-element");
if (step.reflex) {
$element.removeClass('tour-step-element-reflex').off("" + (_this._reflexEvent(step.reflex)) + ".tour-" + _this._options.name);
}
if (step.backdrop) {
_this._hideBackdrop();
}
if (step.onHidden != null) {
return step.onHidden(_this);
}
};
})(this);
this._callOnPromiseDone(promise, hideStepHelper);
return promise;
};
Tour.prototype.showStep = function(i) {
var promise, showStepHelper, skipToPrevious, step;
if (this.ended()) {
this._debug('Tour ended, showStep prevented.');
return this;
}
step = this.getStep(i);
if (!step) {
return;
}
skipToPrevious = i < this._current;
promise = this._makePromise(step.onShow != null ? step.onShow(this, i) : void 0);
showStepHelper = (function(_this) {
return function(e) {
var current_path, path, showPopoverAndOverlay;
_this.setCurrentStep(i);
path = (function() {
switch ({}.toString.call(step.path)) {
case '[object Function]':
return step.path();
case '[object String]':
return this._options.basePath + step.path;
default:
return step.path;
}
}).call(_this);
current_path = [document.location.pathname, document.location.hash].join('');
if (_this._isRedirect(path, current_path)) {
_this._redirect(step, path);
return;
}
if (_this._isOrphan(step)) {
if (!step.orphan) {
_this._debug("Skip the orphan step " + (_this._current + 1) + ".\nOrphan option is false and the element does not exist or is hidden.");
if (skipToPrevious) {
_this._showPrevStep();
} else {
_this._showNextStep();
}
return;
}
_this._debug("Show the orphan step " + (_this._current + 1) + ". Orphans option is true.");
}
if (step.backdrop) {
_this._showBackdrop(!_this._isOrphan(step) ? step.element : void 0);
}
showPopoverAndOverlay = function() {
if (_this.getCurrentStep() !== i) {
return;
}
if ((step.element != null) && step.backdrop) {
_this._showOverlayElement(step);
}
_this._showPopover(step, i);
if (step.onShown != null) {
step.onShown(_this);
}
return _this._debug("Step " + (_this._current + 1) + " of " + _this._options.steps.length);
};
if (step.autoscroll) {
_this._scrollIntoView(step.element, showPopoverAndOverlay);
} else {
showPopoverAndOverlay();
}
if (step.duration) {
return _this.resume();
}
};
})(this);
if (step.delay) {
this._debug("Wait " + step.delay + " milliseconds to show the step " + (this._current + 1));
window.setTimeout((function(_this) {
return function() {
return _this._callOnPromiseDone(promise, showStepHelper);
};
})(this), step.delay);
} else {
this._callOnPromiseDone(promise, showStepHelper);
}
return promise;
};
Tour.prototype.getCurrentStep = function() {
return this._current;
};
Tour.prototype.setCurrentStep = function(value) {
if (value != null) {
this._current = value;
this._setState('current_step', value);
} else {
this._current = this._getState('current_step');
this._current = this._current === null ? null : parseInt(this._current, 10);
}
return this;
};
Tour.prototype._setState = function(key, value) {
var e, keyName;
if (this._options.storage) {
keyName = "" + this._options.name + "_" + key;
try {
this._options.storage.setItem(keyName, value);
} catch (_error) {
e = _error;
if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
this._debug('LocalStorage quota exceeded. State storage failed.');
}
}
return this._options.afterSetState(keyName, value);
} else {
if (this._state == null) {
this._state = {};
}
return this._state[key] = value;
}
};
Tour.prototype._removeState = function(key) {
var keyName;
if (this._options.storage) {
keyName = "" + this._options.name + "_" + key;
this._options.storage.removeItem(keyName);
return this._options.afterRemoveState(keyName);
} else {
if (this._state != null) {
return delete this._state[key];
}
}
};
Tour.prototype._getState = function(key) {
var keyName, value;
if (this._options.storage) {
keyName = "" + this._options.name + "_" + key;
value = this._options.storage.getItem(keyName);
} else {
if (this._state != null) {
value = this._state[key];
}
}
if (value === void 0 || value === 'null') {
value = null;
}
this._options.afterGetState(key, value);
return value;
};
Tour.prototype._showNextStep = function() {
var promise, showNextStepHelper, step;
step = this.getStep(this._current);
showNextStepHelper = (function(_this) {
return function(e) {
return _this.showStep(step.next);
};
})(this);
promise = this._makePromise(step.onNext != null ? step.onNext(this) : void 0);
return this._callOnPromiseDone(promise, showNextStepHelper);
};
Tour.prototype._showPrevStep = function() {
var promise, showPrevStepHelper, step;
step = this.getStep(this._current);
showPrevStepHelper = (function(_this) {
return function(e) {
return _this.showStep(step.prev);
};
})(this);
promise = this._makePromise(step.onPrev != null ? step.onPrev(this) : void 0);
return this._callOnPromiseDone(promise, showPrevStepHelper);
};
Tour.prototype._debug = function(text) {
if (this._options.debug) {
return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text);
}
};
Tour.prototype._isRedirect = function(path, currentPath) {
return (path != null) && path !== '' && (({}.toString.call(path) === '[object RegExp]' && !path.test(currentPath)) || ({}.toString.call(path) === '[object String]' && path.replace(/\?.*$/, '').replace(/\/?$/, '') !== currentPath.replace(/\/?$/, '')));
};
Tour.prototype._redirect = function(step, path) {
if ($.isFunction(step.redirect)) {
return step.redirect.call(this, path);
} else if (step.redirect === true) {
this._debug("Redirect to " + path);
return document.location.href = path;
}
};
Tour.prototype._isOrphan = function(step) {
return (step.element == null) || !$(step.element).length || $(step.element).is(':hidden') && ($(step.element)[0].namespaceURI !== 'http://www.w3.org/2000/svg');
};
Tour.prototype._isLast = function() {
return this._current < this._options.steps.length - 1;
};
Tour.prototype._showPopover = function(step, i) {
var $element, $tip, isOrphan, options;
$(".tour-" + this._options.name).remove();
options = $.extend({}, this._options);
isOrphan = this._isOrphan(step);
step.template = this._template(step, i);
if (isOrphan) {
step.element = 'body';
step.placement = 'top';
}
$element = $(step.element);
$element.addClass("tour-" + this._options.name + "-element tour-" + this._options.name + "-" + i + "-element");
if (step.options) {
$.extend(options, step.options);
}
if (step.reflex && !isOrphan) {
$element.addClass('tour-step-element-reflex');
$element.off("" + (this._reflexEvent(step.reflex)) + ".tour-" + this._options.name);
$element.on("" + (this._reflexEvent(step.reflex)) + ".tour-" + this._options.name, (function(_this) {
return function() {
if (_this._isLast()) {
return _this.next();
} else {
return _this.end();
}
};
})(this));
}
$element.popover({
placement: step.placement,
trigger: 'manual',
title: step.title,
content: step.content,
html: true,
animation: step.animation,
container: step.container,
template: step.template,
selector: step.element
}).popover('show');
$tip = $element.data('bs.popover') ? $element.data('bs.popover').tip() : $element.data('popover').tip();
$tip.attr('id', step.id);
this._reposition($tip, step);
if (isOrphan) {
return this._center($tip);
}
};
Tour.prototype._template = function(step, i) {
var $navigation, $next, $prev, $resume, $template;
$template = $.isFunction(step.template) ? $(step.template(i, step)) : $(step.template);
$navigation = $template.find('.popover-navigation');
$prev = $navigation.find('[data-role="prev"]');
$next = $navigation.find('[data-role="next"]');
$resume = $navigation.find('[data-role="pause-resume"]');
if (this._isOrphan(step)) {
$template.addClass('orphan');
}
$template.addClass("tour-" + this._options.name + " tour-" + this._options.name + "-" + i);
if (step.prev < 0) {
$prev.addClass('disabled');
}
if (step.next < 0) {
$next.addClass('disabled');
}
if (!step.duration) {
$resume.remove();
}
return $template.clone().wrap('<div>').parent().html();
};
Tour.prototype._reflexEvent = function(reflex) {
if ({}.toString.call(reflex) === '[object Boolean]') {
return 'click';
} else {
return reflex;
}
};
Tour.prototype._reposition = function($tip, step) {
var offsetBottom, offsetHeight, offsetRight, offsetWidth, originalLeft, originalTop, tipOffset;
offsetWidth = $tip[0].offsetWidth;
offsetHeight = $tip[0].offsetHeight;
tipOffset = $tip.offset();
originalLeft = tipOffset.left;
originalTop = tipOffset.top;
offsetBottom = $(document).outerHeight() - tipOffset.top - $tip.outerHeight();
if (offsetBottom < 0) {
tipOffset.top = tipOffset.top + offsetBottom;
}
offsetRight = $('html').outerWidth() - tipOffset.left - $tip.outerWidth();
if (offsetRight < 0) {
tipOffset.left = tipOffset.left + offsetRight;
}
if (tipOffset.top < 0) {
tipOffset.top = 0;
}
if (tipOffset.left < 0) {
tipOffset.left = 0;
}
$tip.offset(tipOffset);
if (step.placement === 'bottom' || step.placement === 'top') {
if (originalLeft !== tipOffset.left) {
return this._replaceArrow($tip, (tipOffset.left - originalLeft) * 2, offsetWidth, 'left');
}
} else {
if (originalTop !== tipOffset.top) {
return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, 'top');
}
}
};
Tour.prototype._center = function($tip) {
return $tip.css('top', $(window).outerHeight() / 2 - $tip.outerHeight() / 2);
};
Tour.prototype._replaceArrow = function($tip, delta, dimension, position) {
return $tip.find('.arrow').css(position, delta ? 50 * (1 - delta / dimension) + '%' : '');
};
Tour.prototype._scrollIntoView = function(element, callback) {
var $element, $window, counter, offsetTop, scrollTop, windowHeight;
$element = $(element);
if (!$element.length) {
return callback();
}
$window = $(window);
offsetTop = $element.offset().top;
windowHeight = $window.height();
scrollTop = Math.max(0, offsetTop - (windowHeight / 2));
this._debug("Scroll into view. ScrollTop: " + scrollTop + ". Element offset: " + offsetTop + ". Window height: " + windowHeight + ".");
counter = 0;
return $('body, html').stop(true, true).animate({
scrollTop: Math.ceil(scrollTop)
}, (function(_this) {
return function() {
if (++counter === 2) {
callback();
return _this._debug("Scroll into view.\nAnimation end element offset: " + ($element.offset().top) + ".\nWindow height: " + ($window.height()) + ".");
}
};
})(this));
};
Tour.prototype._onResize = function(callback, timeout) {
return $(window).on("resize.tour-" + this._options.name, function() {
clearTimeout(timeout);
return timeout = setTimeout(callback, 100);
});
};
Tour.prototype._initMouseNavigation = function() {
var _this;
_this = this;
return $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']", (function(_this) {
return function(e) {
e.preventDefault();
return _this.next();
};
})(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']", (function(_this) {
return function(e) {
e.preventDefault();
return _this.prev();
};
})(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']", (function(_this) {
return function(e) {
e.preventDefault();
return _this.end();
};
})(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']", function(e) {
var $this;
e.preventDefault();
$this = $(this);
$this.text(_this._paused ? $this.data('pause-text') : $this.data('resume-text'));
if (_this._paused) {
return _this.resume();
} else {
return _this.pause();
}
});
};
Tour.prototype._initKeyboardNavigation = function() {
if (!this._options.keyboard) {
return;
}
return $(document).on("keyup.tour-" + this._options.name, (function(_this) {
return function(e) {
if (!e.which) {
return;
}
switch (e.which) {
case 39:
e.preventDefault();
if (_this._isLast()) {
return _this.next();
} else {
return _this.end();
}
break;
case 37:
e.preventDefault();
if (_this._current > 0) {
return _this.prev();
}
break;
case 27:
e.preventDefault();
return _this.end();
}
};
})(this));
};
Tour.prototype._makePromise = function(result) {
if (result && $.isFunction(result.then)) {
return result;
} else {
return null;
}
};
Tour.prototype._callOnPromiseDone = function(promise, cb, arg) {
if (promise) {
return promise.then((function(_this) {
return function(e) {
return cb.call(_this, arg);
};
})(this));
} else {
return cb.call(this, arg);
}
};
Tour.prototype._showBackdrop = function(element) {
if (this.backdrop.backgroundShown) {
return;
}
this.backdrop = $('<div>', {
"class": 'tour-backdrop'
});
this.backdrop.backgroundShown = true;
return $('body').append(this.backdrop);
};
Tour.prototype._hideBackdrop = function() {
this._hideOverlayElement();
return this._hideBackground();
};
Tour.prototype._hideBackground = function() {
if (this.backdrop) {
this.backdrop.remove();
this.backdrop.overlay = null;
return this.backdrop.backgroundShown = false;
}
};
Tour.prototype._showOverlayElement = function(step) {
var $element, elementData;
$element = $(step.element);
if (!$element || $element.length === 0 || this.backdrop.overlayElementShown) {
return;
}
this.backdrop.overlayElementShown = true;
this.backdrop.$element = $element.addClass('tour-step-backdrop');
this.backdrop.$background = $('<div>', {
"class": 'tour-step-background'
});
elementData = {
width: $element.innerWidth(),
height: $element.innerHeight(),
offset: $element.offset()
};
this.backdrop.$background.appendTo('body');
if (step.backdropPadding) {
elementData = this._applyBackdropPadding(step.backdropPadding, elementData);
}
return this.backdrop.$background.width(elementData.width).height(elementData.height).offset(elementData.offset);
};
Tour.prototype._hideOverlayElement = function() {
if (!this.backdrop.overlayElementShown) {
return;
}
this.backdrop.$element.removeClass('tour-step-backdrop');
this.backdrop.$background.remove();
this.backdrop.$element = null;
this.backdrop.$background = null;
return this.backdrop.overlayElementShown = false;
};
Tour.prototype._applyBackdropPadding = function(padding, data) {
if (typeof padding === 'object') {
if (padding.top == null) {
padding.top = 0;
}
if (padding.right == null) {
padding.right = 0;
}
if (padding.bottom == null) {
padding.bottom = 0;
}
if (padding.left == null) {
padding.left = 0;
}
data.offset.top = data.offset.top - padding.top;
data.offset.left = data.offset.left - padding.left;
data.width = data.width + padding.left + padding.right;
data.height = data.height + padding.top + padding.bottom;
} else {
data.offset.top = data.offset.top - padding;
data.offset.left = data.offset.left - padding;
data.width = data.width + (padding * 2);
data.height = data.height + (padding * 2);
}
return data;
};
Tour.prototype._clearTimer = function() {
window.clearTimeout(this._timer);
this._timer = null;
return this._duration = null;
};
return Tour;
})();
return window.Tour = Tour;
})(jQuery, window);
Vendored Executable → Regular
View File
@@ -1,881 +0,0 @@
/*!
handlebars v3.0.3
Copyright (C) 2011-2014 by Yehuda Katz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@license
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define(factory);
else if(typeof exports === 'object')
exports["Handlebars"] = factory();
else
root["Handlebars"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var _interopRequireWildcard = __webpack_require__(7)['default'];
exports.__esModule = true;
var _import = __webpack_require__(1);
var base = _interopRequireWildcard(_import);
// Each of these augment the Handlebars object. No need to setup here.
// (This is done to easily share code between commonjs and browse envs)
var _SafeString = __webpack_require__(2);
var _SafeString2 = _interopRequireWildcard(_SafeString);
var _Exception = __webpack_require__(3);
var _Exception2 = _interopRequireWildcard(_Exception);
var _import2 = __webpack_require__(4);
var Utils = _interopRequireWildcard(_import2);
var _import3 = __webpack_require__(5);
var runtime = _interopRequireWildcard(_import3);
var _noConflict = __webpack_require__(6);
var _noConflict2 = _interopRequireWildcard(_noConflict);
// For compatibility and usage outside of module systems, make the Handlebars object a namespace
function create() {
var hb = new base.HandlebarsEnvironment();
Utils.extend(hb, base);
hb.SafeString = _SafeString2['default'];
hb.Exception = _Exception2['default'];
hb.Utils = Utils;
hb.escapeExpression = Utils.escapeExpression;
hb.VM = runtime;
hb.template = function (spec) {
return runtime.template(spec, hb);
};
return hb;
}
var inst = create();
inst.create = create;
_noConflict2['default'](inst);
inst['default'] = inst;
exports['default'] = inst;
module.exports = exports['default'];
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var _interopRequireWildcard = __webpack_require__(7)['default'];
exports.__esModule = true;
exports.HandlebarsEnvironment = HandlebarsEnvironment;
exports.createFrame = createFrame;
var _import = __webpack_require__(4);
var Utils = _interopRequireWildcard(_import);
var _Exception = __webpack_require__(3);
var _Exception2 = _interopRequireWildcard(_Exception);
var VERSION = '3.0.1';
exports.VERSION = VERSION;
var COMPILER_REVISION = 6;
exports.COMPILER_REVISION = COMPILER_REVISION;
var REVISION_CHANGES = {
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
2: '== 1.0.0-rc.3',
3: '== 1.0.0-rc.4',
4: '== 1.x.x',
5: '== 2.0.0-alpha.x',
6: '>= 2.0.0-beta.1'
};
exports.REVISION_CHANGES = REVISION_CHANGES;
var isArray = Utils.isArray,
isFunction = Utils.isFunction,
toString = Utils.toString,
objectType = '[object Object]';
function HandlebarsEnvironment(helpers, partials) {
this.helpers = helpers || {};
this.partials = partials || {};
registerDefaultHelpers(this);
}
HandlebarsEnvironment.prototype = {
constructor: HandlebarsEnvironment,
logger: logger,
log: log,
registerHelper: function registerHelper(name, fn) {
if (toString.call(name) === objectType) {
if (fn) {
throw new _Exception2['default']('Arg not supported with multiple helpers');
}
Utils.extend(this.helpers, name);
} else {
this.helpers[name] = fn;
}
},
unregisterHelper: function unregisterHelper(name) {
delete this.helpers[name];
},
registerPartial: function registerPartial(name, partial) {
if (toString.call(name) === objectType) {
Utils.extend(this.partials, name);
} else {
if (typeof partial === 'undefined') {
throw new _Exception2['default']('Attempting to register a partial as undefined');
}
this.partials[name] = partial;
}
},
unregisterPartial: function unregisterPartial(name) {
delete this.partials[name];
}
};
function registerDefaultHelpers(instance) {
instance.registerHelper('helperMissing', function () {
if (arguments.length === 1) {
// A missing field in a {{foo}} constuct.
return undefined;
} else {
// Someone is actually trying to call something, blow up.
throw new _Exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"');
}
});
instance.registerHelper('blockHelperMissing', function (context, options) {
var inverse = options.inverse,
fn = options.fn;
if (context === true) {
return fn(this);
} else if (context === false || context == null) {
return inverse(this);
} else if (isArray(context)) {
if (context.length > 0) {
if (options.ids) {
options.ids = [options.name];
}
return instance.helpers.each(context, options);
} else {
return inverse(this);
}
} else {
if (options.data && options.ids) {
var data = createFrame(options.data);
data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name);
options = { data: data };
}
return fn(context, options);
}
});
instance.registerHelper('each', function (context, options) {
if (!options) {
throw new _Exception2['default']('Must pass iterator to #each');
}
var fn = options.fn,
inverse = options.inverse,
i = 0,
ret = '',
data = undefined,
contextPath = undefined;
if (options.data && options.ids) {
contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.';
}
if (isFunction(context)) {
context = context.call(this);
}
if (options.data) {
data = createFrame(options.data);
}
function execIteration(field, index, last) {
if (data) {
data.key = field;
data.index = index;
data.first = index === 0;
data.last = !!last;
if (contextPath) {
data.contextPath = contextPath + field;
}
}
ret = ret + fn(context[field], {
data: data,
blockParams: Utils.blockParams([context[field], field], [contextPath + field, null])
});
}
if (context && typeof context === 'object') {
if (isArray(context)) {
for (var j = context.length; i < j; i++) {
execIteration(i, i, i === context.length - 1);
}
} else {
var priorKey = undefined;
for (var key in context) {
if (context.hasOwnProperty(key)) {
// We're running the iterations one step out of sync so we can detect
// the last iteration without have to scan the object twice and create
// an itermediate keys array.
if (priorKey) {
execIteration(priorKey, i - 1);
}
priorKey = key;
i++;
}
}
if (priorKey) {
execIteration(priorKey, i - 1, true);
}
}
}
if (i === 0) {
ret = inverse(this);
}
return ret;
});
instance.registerHelper('if', function (conditional, options) {
if (isFunction(conditional)) {
conditional = conditional.call(this);
}
// Default behavior is to render the positive path if the value is truthy and not empty.
// The `includeZero` option may be set to treat the condtional as purely not empty based on the
// behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
if (!options.hash.includeZero && !conditional || Utils.isEmpty(conditional)) {
return options.inverse(this);
} else {
return options.fn(this);
}
});
instance.registerHelper('unless', function (conditional, options) {
return instance.helpers['if'].call(this, conditional, { fn: options.inverse, inverse: options.fn, hash: options.hash });
});
instance.registerHelper('with', function (context, options) {
if (isFunction(context)) {
context = context.call(this);
}
var fn = options.fn;
if (!Utils.isEmpty(context)) {
if (options.data && options.ids) {
var data = createFrame(options.data);
data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]);
options = { data: data };
}
return fn(context, options);
} else {
return options.inverse(this);
}
});
instance.registerHelper('log', function (message, options) {
var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
instance.log(level, message);
});
instance.registerHelper('lookup', function (obj, field) {
return obj && obj[field];
});
}
var logger = {
methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },
// State enum
DEBUG: 0,
INFO: 1,
WARN: 2,
ERROR: 3,
level: 1,
// Can be overridden in the host environment
log: function log(level, message) {
if (typeof console !== 'undefined' && logger.level <= level) {
var method = logger.methodMap[level];
(console[method] || console.log).call(console, message); // eslint-disable-line no-console
}
}
};
exports.logger = logger;
var log = logger.log;
exports.log = log;
function createFrame(object) {
var frame = Utils.extend({}, object);
frame._parent = object;
return frame;
}
/* [args, ]options */
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
// Build out our basic SafeString type
function SafeString(string) {
this.string = string;
}
SafeString.prototype.toString = SafeString.prototype.toHTML = function () {
return '' + this.string;
};
exports['default'] = SafeString;
module.exports = exports['default'];
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
function Exception(message, node) {
var loc = node && node.loc,
line = undefined,
column = undefined;
if (loc) {
line = loc.start.line;
column = loc.start.column;
message += ' - ' + line + ':' + column;
}
var tmp = Error.prototype.constructor.call(this, message);
// Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
for (var idx = 0; idx < errorProps.length; idx++) {
this[errorProps[idx]] = tmp[errorProps[idx]];
}
if (Error.captureStackTrace) {
Error.captureStackTrace(this, Exception);
}
if (loc) {
this.lineNumber = line;
this.column = column;
}
}
Exception.prototype = new Error();
exports['default'] = Exception;
module.exports = exports['default'];
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
exports.extend = extend;
// Older IE versions do not directly support indexOf so we must implement our own, sadly.
exports.indexOf = indexOf;
exports.escapeExpression = escapeExpression;
exports.isEmpty = isEmpty;
exports.blockParams = blockParams;
exports.appendContextPath = appendContextPath;
var escape = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'\'': '&#x27;',
'`': '&#x60;'
};
var badChars = /[&<>"'`]/g,
possible = /[&<>"'`]/;
function escapeChar(chr) {
return escape[chr];
}
function extend(obj /* , ...source */) {
for (var i = 1; i < arguments.length; i++) {
for (var key in arguments[i]) {
if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
obj[key] = arguments[i][key];
}
}
}
return obj;
}
var toString = Object.prototype.toString;
exports.toString = toString;
// Sourced from lodash
// https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
/*eslint-disable func-style, no-var */
var isFunction = function isFunction(value) {
return typeof value === 'function';
};
// fallback for older versions of Chrome and Safari
/* istanbul ignore next */
if (isFunction(/x/)) {
exports.isFunction = isFunction = function (value) {
return typeof value === 'function' && toString.call(value) === '[object Function]';
};
}
var isFunction;
exports.isFunction = isFunction;
/*eslint-enable func-style, no-var */
/* istanbul ignore next */
var isArray = Array.isArray || function (value) {
return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false;
};exports.isArray = isArray;
function indexOf(array, value) {
for (var i = 0, len = array.length; i < len; i++) {
if (array[i] === value) {
return i;
}
}
return -1;
}
function escapeExpression(string) {
if (typeof string !== 'string') {
// don't escape SafeStrings, since they're already safe
if (string && string.toHTML) {
return string.toHTML();
} else if (string == null) {
return '';
} else if (!string) {
return string + '';
}
// Force a string conversion as this will be done by the append regardless and
// the regex test will do this transparently behind the scenes, causing issues if
// an object's to string has escaped characters in it.
string = '' + string;
}
if (!possible.test(string)) {
return string;
}
return string.replace(badChars, escapeChar);
}
function isEmpty(value) {
if (!value && value !== 0) {
return true;
} else if (isArray(value) && value.length === 0) {
return true;
} else {
return false;
}
}
function blockParams(params, ids) {
params.path = ids;
return params;
}
function appendContextPath(contextPath, id) {
return (contextPath ? contextPath + '.' : '') + id;
}
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var _interopRequireWildcard = __webpack_require__(7)['default'];
exports.__esModule = true;
exports.checkRevision = checkRevision;
// TODO: Remove this line and break up compilePartial
exports.template = template;
exports.wrapProgram = wrapProgram;
exports.resolvePartial = resolvePartial;
exports.invokePartial = invokePartial;
exports.noop = noop;
var _import = __webpack_require__(4);
var Utils = _interopRequireWildcard(_import);
var _Exception = __webpack_require__(3);
var _Exception2 = _interopRequireWildcard(_Exception);
var _COMPILER_REVISION$REVISION_CHANGES$createFrame = __webpack_require__(1);
function checkRevision(compilerInfo) {
var compilerRevision = compilerInfo && compilerInfo[0] || 1,
currentRevision = _COMPILER_REVISION$REVISION_CHANGES$createFrame.COMPILER_REVISION;
if (compilerRevision !== currentRevision) {
if (compilerRevision < currentRevision) {
var runtimeVersions = _COMPILER_REVISION$REVISION_CHANGES$createFrame.REVISION_CHANGES[currentRevision],
compilerVersions = _COMPILER_REVISION$REVISION_CHANGES$createFrame.REVISION_CHANGES[compilerRevision];
throw new _Exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
} else {
// Use the embedded version info since the runtime doesn't know about this revision yet
throw new _Exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
}
}
}
function template(templateSpec, env) {
/* istanbul ignore next */
if (!env) {
throw new _Exception2['default']('No environment passed to template');
}
if (!templateSpec || !templateSpec.main) {
throw new _Exception2['default']('Unknown template object: ' + typeof templateSpec);
}
// Note: Using env.VM references rather than local var references throughout this section to allow
// for external users to override these as psuedo-supported APIs.
env.VM.checkRevision(templateSpec.compiler);
function invokePartialWrapper(partial, context, options) {
if (options.hash) {
context = Utils.extend({}, context, options.hash);
}
partial = env.VM.resolvePartial.call(this, partial, context, options);
var result = env.VM.invokePartial.call(this, partial, context, options);
if (result == null && env.compile) {
options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env);
result = options.partials[options.name](context, options);
}
if (result != null) {
if (options.indent) {
var lines = result.split('\n');
for (var i = 0, l = lines.length; i < l; i++) {
if (!lines[i] && i + 1 === l) {
break;
}
lines[i] = options.indent + lines[i];
}
result = lines.join('\n');
}
return result;
} else {
throw new _Exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode');
}
}
// Just add water
var container = {
strict: function strict(obj, name) {
if (!(name in obj)) {
throw new _Exception2['default']('"' + name + '" not defined in ' + obj);
}
return obj[name];
},
lookup: function lookup(depths, name) {
var len = depths.length;
for (var i = 0; i < len; i++) {
if (depths[i] && depths[i][name] != null) {
return depths[i][name];
}
}
},
lambda: function lambda(current, context) {
return typeof current === 'function' ? current.call(context) : current;
},
escapeExpression: Utils.escapeExpression,
invokePartial: invokePartialWrapper,
fn: function fn(i) {
return templateSpec[i];
},
programs: [],
program: function program(i, data, declaredBlockParams, blockParams, depths) {
var programWrapper = this.programs[i],
fn = this.fn(i);
if (data || depths || blockParams || declaredBlockParams) {
programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths);
} else if (!programWrapper) {
programWrapper = this.programs[i] = wrapProgram(this, i, fn);
}
return programWrapper;
},
data: function data(value, depth) {
while (value && depth--) {
value = value._parent;
}
return value;
},
merge: function merge(param, common) {
var obj = param || common;
if (param && common && param !== common) {
obj = Utils.extend({}, common, param);
}
return obj;
},
noop: env.VM.noop,
compilerInfo: templateSpec.compiler
};
function ret(context) {
var options = arguments[1] === undefined ? {} : arguments[1];
var data = options.data;
ret._setup(options);
if (!options.partial && templateSpec.useData) {
data = initData(context, data);
}
var depths = undefined,
blockParams = templateSpec.useBlockParams ? [] : undefined;
if (templateSpec.useDepths) {
depths = options.depths ? [context].concat(options.depths) : [context];
}
return templateSpec.main.call(container, context, container.helpers, container.partials, data, blockParams, depths);
}
ret.isTop = true;
ret._setup = function (options) {
if (!options.partial) {
container.helpers = container.merge(options.helpers, env.helpers);
if (templateSpec.usePartial) {
container.partials = container.merge(options.partials, env.partials);
}
} else {
container.helpers = options.helpers;
container.partials = options.partials;
}
};
ret._child = function (i, data, blockParams, depths) {
if (templateSpec.useBlockParams && !blockParams) {
throw new _Exception2['default']('must pass block params');
}
if (templateSpec.useDepths && !depths) {
throw new _Exception2['default']('must pass parent depths');
}
return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths);
};
return ret;
}
function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
function prog(context) {
var options = arguments[1] === undefined ? {} : arguments[1];
return fn.call(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), depths && [context].concat(depths));
}
prog.program = i;
prog.depth = depths ? depths.length : 0;
prog.blockParams = declaredBlockParams || 0;
return prog;
}
function resolvePartial(partial, context, options) {
if (!partial) {
partial = options.partials[options.name];
} else if (!partial.call && !options.name) {
// This is a dynamic partial that returned a string
options.name = partial;
partial = options.partials[partial];
}
return partial;
}
function invokePartial(partial, context, options) {
options.partial = true;
if (partial === undefined) {
throw new _Exception2['default']('The partial ' + options.name + ' could not be found');
} else if (partial instanceof Function) {
return partial(context, options);
}
}
function noop() {
return '';
}
function initData(context, data) {
if (!data || !('root' in data)) {
data = data ? _COMPILER_REVISION$REVISION_CHANGES$createFrame.createFrame(data) : {};
data.root = context;
}
return data;
}
/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global) {'use strict';
exports.__esModule = true;
/*global window */
exports['default'] = function (Handlebars) {
/* istanbul ignore next */
var root = typeof global !== 'undefined' ? global : window,
$Handlebars = root.Handlebars;
/* istanbul ignore next */
Handlebars.noConflict = function () {
if (root.Handlebars === Handlebars) {
root.Handlebars = $Handlebars;
}
};
};
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ },
/* 7 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
exports["default"] = function (obj) {
return obj && obj.__esModule ? obj : {
"default": obj
};
};
exports.__esModule = true;
/***/ }
/******/ ])
});
;
@@ -1,6 +1,7 @@
define([
"mvc/base-mvc",
"utils/localization"
"utils/localization",
"ui/editable-text",
], function( baseMVC, _l ){
// =============================================================================
/** A view on any model that has a 'annotation' attribute
@@ -1,225 +0,0 @@
define(['utils/utils', 'mvc/tools', 'mvc/upload/upload-view', 'mvc/ui/ui-misc',
'mvc/history/options-menu', 'mvc/history/history-panel-edit-current', 'mvc/tools/tools-form'],
function( Utils, Tools, Upload, Ui, optionsMenu, HistoryPanel, ToolsForm ) {
/* Builds the center panel */
var CenterPanel = Backbone.View.extend({
initialize: function( options ) {
this.options = Utils.merge( options, {} );
this.setElement( this._template() );
var self = this;
this.$( '#galaxy_main' ).on( 'load', function() {
var location = this.contentWindow && this.contentWindow.location;
if ( location && location.host ) {
$( this ).show();
self.prev && self.prev.remove();
self.$( '#center-panel' ).hide();
Galaxy.trigger( 'galaxy_main:load', {
fullpath: location.pathname + location.search + location.hash,
pathname: location.pathname,
search : location.search,
hash : location.hash
});
}
});
var params = $.extend( {}, Galaxy.params );
if ( params.tool_id !== 'upload1' && ( params.tool_id || params.job_id ) ) {
params.tool_id && ( params.id = params.tool_id );
this.display( new ToolsForm.View( params ) );
} else {
this.$( '#galaxy_main' ).prop( 'src', Galaxy.root + (
( params.workflow_id && ( 'workflow/run?id=' + params.workflow_id ) ) ||
( params.m_c && ( params.m_c + '/' + params.m_a ) ) ||
'root/welcome'
));
}
},
display: function( view ) {
this.prev && this.prev.remove();
this.prev = view;
this.$( '#galaxy_main' ).hide();
this.$( '#center-panel' ).scrollTop( 0 ).append( view.$el ).show();
},
_template: function() {
return '<div style="position: absolute; width: 100%; height: 100%">' +
'<iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;"/>' +
'<div id="center-panel" style="position: absolute; width: 100%; height: 100%; padding: 10px; overflow: auto;"/>' +
'</div>';
}
});
/* Builds the tool panel on the left */
var LeftPanel = Backbone.View.extend({
initialize: function( options ) {
this.options = Utils.merge( options, {} );
this.setElement( this._template() );
// create tool search, tool panel, and tool panel view.
if ( Galaxy.user.id || !Galaxy.config.require_login ) {
var tool_search = new Tools.ToolSearch({
spinner_url : options.spinner_url,
search_url : options.search_url,
hidden : false
});
var tools = new Tools.ToolCollection( options.toolbox );
var tool_panel = new Tools.ToolPanel({
tool_search : tool_search,
tools : tools,
layout : options.toolbox_in_panel
});
tool_panel_view = new Tools.ToolPanelView({ model: tool_panel });
// add tool panel to Galaxy object
Galaxy.toolPanel = tool_panel;
// if there are tools, render panel and display everything
if (tool_panel.get( 'layout' ).size() > 0) {
tool_panel_view.render();
this.$( '.toolMenu' ).show();
}
this.$el.prepend( tool_panel_view.$el );
// add internal workflow list
this.$( '#internal-workflows' ).append( this._templateTool({
title : 'All workflows',
href : 'workflow/list_for_run'
}) )
for ( var i in options.stored_workflow_menu_entries ) {
var m = options.stored_workflow_menu_entries[ i ];
this.$( '#internal-workflows' ).append( this._templateTool({
title : m.stored_workflow.name,
href : 'workflow/run?id=' + m.encoded_stored_workflow_id
}) );
}
// minsize init hint
this.$( 'a[minsizehint]' ).click( function() {
if ( parent.handle_minwidth_hint ) {
parent.handle_minwidth_hint( $( this ).attr( 'minsizehint' ) );
}
});
// add upload plugin
Galaxy.upload = new Upload( options );
// define components (is used in app-view.js)
this.components = {
header : {
title : 'Tools',
buttons : [ Galaxy.upload ]
}
}
}
},
_templateTool: function( options ) {
return '<div class="toolTitle">' +
'<a href="' + Galaxy.root + options.href + '" target="galaxy_main">' + options.title + '</a>' +
'</div>';
},
_template: function() {
return '<div class="toolMenuContainer">' +
'<div class="toolMenu" style="display: none">' +
'<div id="search-no-results" style="display: none; padding-top: 5px">' +
'<em><strong>Search did not match any tools.</strong></em>' +
'</div>' +
'</div>' +
'<div class="toolSectionPad"/>' +
'<div class="toolSectionPad"/>' +
'<div class="toolSectionTitle" id="title_XXinternalXXworkflow">' +
'<span>Workflows</span>' +
'</div>' +
'<div id="internal-workflows" class="toolSectionBody">' +
'<div class="toolSectionBg"/>' +
'</div>' +
'</div>';
}
});
/* Builds the history panel on the right */
var RightPanel = Backbone.View.extend({
initialize: function(options) {
this.options = Utils.merge( options, {} );
this.setElement( this._template() );
var headerButtons = [];
// this button re-fetches the history and contents and re-renders the history panel
var buttonRefresh = new Ui.ButtonLink({
id : 'history-refresh-button',
title : 'Refresh history',
cls : 'panel-header-button',
icon : 'fa fa-refresh',
onclick : function() {
if( top.Galaxy && top.Galaxy.currHistoryPanel ) {
top.Galaxy.currHistoryPanel.loadCurrentHistory();
}
}
});
headerButtons.push( buttonRefresh );
// opens a drop down menu with history related functions (like view all, delete, share, etc.)
var buttonOptions = new Ui.ButtonLink({
id : 'history-options-button',
title : 'History options',
cls : 'panel-header-button',
target : 'galaxy_main',
icon : 'fa fa-cog',
href : Galaxy.root + 'root/history_options'
});
headerButtons.push( buttonOptions );
// goes to a page showing all the users histories in panel form (for logged in users)
if( !Galaxy.user.isAnonymous() ){
var buttonViewMulti = new Ui.ButtonLink({
id : 'history-view-multi-button',
title : 'View all histories',
cls : 'panel-header-button',
icon : 'fa fa-columns',
href : Galaxy.root + 'history/view_multiple'
});
headerButtons.push( buttonViewMulti );
}
// define components (is used in app-view.js)
this.components = {
header : {
title : 'History',
cls : 'history-panel-header',
buttons : headerButtons
},
body : {
cls : 'unified-panel-body-background',
}
};
// build history options menu
Galaxy.historyOptionsMenu = optionsMenu( buttonOptions.$el, {
anonymous : Galaxy.user.isAnonymous(),
purgeAllowed : Galaxy.config.allow_user_dataset_purge,
root : Galaxy.root
});
// load current history
Galaxy.currHistoryPanel = new HistoryPanel.CurrentHistoryPanel({
el : this.$el,
purgeAllowed : Galaxy.config.allow_user_dataset_purge,
linkTarget : 'galaxy_main',
$scrollContainer: function(){ return this.$el.parent(); }
});
Galaxy.currHistoryPanel.connectToQuotaMeter( Galaxy.quotaMeter );
Galaxy.currHistoryPanel.listenToGalaxy( Galaxy );
Galaxy.currHistoryPanel.loadCurrentHistory();
},
// body template
_template: function() {
return '<div id="current-history-panel" class="history-panel"/>';
}
});
return {
left : LeftPanel,
center : CenterPanel,
right : RightPanel
};
});
@@ -1,19 +0,0 @@
define([ 'utils/utils' ], function( Utils ) {
return {
center: Backbone.View.extend({
initialize: function() {
this.setElement( Utils.iframe( Galaxy.root + 'static/welcome.html' ) );
}
}),
right: Backbone.View.extend({
initialize: function() {
this.components = {
header: {
title: 'Login required'
}
}
this.setElement( Utils.iframe( Galaxy.root + 'user/login' ) );
}
})
}
});
-148
View File
@@ -1,148 +0,0 @@
/**
This is the entrance point for the Galaxy UI.
*/
define(['utils/utils', 'galaxy.masthead', 'galaxy.menu', 'galaxy.frame',
'mvc/ui/ui-portlet', 'mvc/ui/ui-misc', 'mvc/ui/ui-modal',
'mvc/user/user-quotameter', 'mvc/app/app-login', 'mvc/app/app-analysis'],
function( Utils, Masthead, Menu, Frame, Portlet, Ui, Modal, QuotaMeter, Login, Analysis ) {
return Backbone.View.extend({
initialize: function( options ) {
this.options = Utils.merge( options, {} );
this.setElement( this._template( options ) );
// register this view
Galaxy.app = this;
// url request parameters
Galaxy.params = this.options.params;
// shared backbone router
Galaxy.router = new Backbone.Router();
// configure body
$( 'body' ).append( this.$el );
ensure_dd_helper();
// adjust parent container
var $container = $( this.$el.parent() ).attr( 'scroll', 'no' ).addClass( 'full-content' );
if ( this.options.message_box_visible ) {
$container.addClass( 'has-message-box' );
this.$( '#messagebox' ).show();
}
if ( this.options.show_inactivity_warning ) {
$container.addClass( 'has-inactivity-box' );
this.$( '#inactivebox' ).show();
}
// load global galaxy objects
if ( !Galaxy.masthead ) {
Galaxy.masthead = new Masthead.GalaxyMasthead( this.options );
Galaxy.modal = new Modal.View();
Galaxy.frame = new Frame.GalaxyFrame();
// construct default menu options
Galaxy.menu = new Menu.GalaxyMenu({
masthead : Galaxy.masthead,
config : this.options
});
// set up the quota meter (And fetch the current user data from trans)
// add quota meter to masthead
Galaxy.quotaMeter = new QuotaMeter.UserQuotaMeter({
model : Galaxy.user,
el : Galaxy.masthead.$( '.quota-meter-container' )
}).render();
}
// build page
if ( Galaxy.config.require_login && !Galaxy.user.id ) {
this.build( Login );
} else {
this.build( Analysis );
}
},
/** Display content */
display: function ( view, target ) {
// TODO: Remove this line after select2 update
$( '.select2-hidden-accessible' ).remove();
this.panels && this.panels[ target || 'center' ].display( view );
},
/** Build all panels **/
build: function( Views ) {
this.panels = [];
var options = $.extend( true, {}, this.options );
var panel_ids = [ 'center', 'left', 'right' ];
for ( var i in panel_ids ) {
var id = panel_ids[ i ];
this.$( '#' + id ).remove();
if ( !Views[ id ] ) {
this.$( '#center' ).css( id, '0' );
continue;
}
var view = this.panels[ id ] = new Views[ id ]( options );
if ( id == 'center' ) {
this.$el.append( $( '<div id="' + id + '"/>' ).addClass( 'inbound' ).append( view.$el ) );
} else {
var components = Utils.merge( view.components, {
header : {
title : '',
cls : '',
buttons : []
},
body : {
cls : ''
}
});
var $panel = $( this._templatePanel( id ) );
$panel.find('.panel-header-text').html( components.header.title );
$panel.find('.unified-panel-header-inner').addClass( components.header.cls );
for ( var i in components.header.buttons ) {
$panel.find('.panel-header-buttons').append( components.header.buttons[ i ].$el );
}
$panel.find('.unified-panel-body').addClass( components.body.cls ).append( view.$el );
var panel = new Panel( {
center : this.$( '#center' ),
panel : $panel,
drag : $panel.find('.unified-panel-footer > .drag' ),
toggle : $panel.find('.unified-panel-footer > .panel-collapse' ),
right : id == 'right'
} );
this.$el.append( $panel );
}
}
},
/** Template for left/right panel */
_templatePanel: function( id ) {
return '<div id="' + id + '">' +
'<div class="unified-panel-header" unselectable="on">' +
'<div class="unified-panel-header-inner">' +
'<div class="panel-header-buttons" style="float: right"/>' +
'<div class="panel-header-text"/>' +
'</div>' +
'</div>' +
'<div class="unified-panel-body"/>' +
'<div class="unified-panel-footer">' +
'<div class="panel-collapse ' + id + '"/>' +
'<div class="drag"/>' +
'</div>' +
'</div>';
},
/** Main template **/
_template: function() {
return '<div id="everything" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">' +
'<div id="background"/>' +
'<div id="messagebox" class="panel-' + Galaxy.config.message_box_class + '-message" style="display: none;">' +
Galaxy.config.message_box_content +
'</div>' +
'<div id="inactivebox" class="panel-warning-message" style="display: none;">' +
Galaxy.config.inactivity_box_content +
' <a href="' + Galaxy.root + 'user/resend_verification">Resend verification.</a>' +
'</div>' +
'</div>';
}
});
});
+8 -3
View File
@@ -1,7 +1,12 @@
define([
'libs/underscore',
'libs/backbone',
'utils/add-logging',
'utils/localization'
], function( addLogging, _l ){
], function( _, Backbone, addLogging, _l ){
'use strict';
//==============================================================================
/** @class Mixin to add logging capabilities to an object.
* Designed to allow switching an objects log output off/on at one central
@@ -64,7 +69,7 @@ var SessionStorageModel = Backbone.Model.extend({
_checkEnabledSessionStorage : function(){
try {
return sessionStorage.length;
return window.sessionStorage.length >= 0;
} catch( err ){
alert( 'Please enable cookies in your browser for this Galaxy site' );
return false;
@@ -166,7 +171,7 @@ function mixin( mixinHash1, /* mixinHash2, etc: ... variadic */ propsHash ){
* @example:
* see hda-model for searchAttribute and searchAliases definition examples.
* see history-contents.matches for how collections are filtered
* and see readonly-history-panel.searchHdas for how user input is connected to the filtering
* and see readonly-history-view.searchHdas for how user input is connected to the filtering
*/
var SearchableModelMixin = {
@@ -1,8 +1,12 @@
define([
"libs/bibtex",
"mvc/base-mvc",
"utils/localization"
], function( baseMVC, _l ){
], function( parseBibtex, baseMVC, _l ){
/* global Backbone */
// we use amd here to require, but bibtex uses a global or commonjs pattern.
// webpack will load via commonjs and plain requirejs will load as global. Check both
parseBibtex = parseBibtex || window.BibtexParser;
var logNamespace = 'citation';
//==============================================================================
@@ -13,13 +17,13 @@ var logNamespace = 'citation';
var Citation = Backbone.Model.extend( baseMVC.LoggableMixin ).extend( {
_logNamespace : logNamespace,
initialize: function( ) {
var bibtex = this.attributes.content;
var entry = new BibtexParser(bibtex).entries[0];
initialize: function() {
var bibtex = this.get( 'content' );
var entry = parseBibtex(bibtex).entries[0];
this.entry = entry;
this._fields = {};
var rawFields = entry.Fields;
for(key in rawFields) {
for(var key in rawFields) {
var value = rawFields[ key ];
var lowerKey = key.toLowerCase();
this._fields[ lowerKey ] = value;
@@ -40,7 +44,7 @@ var BaseCitationCollection = Backbone.Collection.extend( baseMVC.LoggableMixin )
_logNamespace : logNamespace,
/** root api url */
urlRoot : galaxy_config.root + 'api',
urlRoot : Galaxy.root + 'api',
partial : true, // Assume some tools in history/workflow may not be properly annotated yet.
model : Citation,
} );
@@ -60,6 +64,7 @@ var ToolCitationCollection = BaseCitationCollection.extend( {
partial : false, // If a tool has citations, assume they are complete.
} );
//==============================================================================
return {
Citation : Citation,
@@ -4,7 +4,8 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( DC_LI, DATASET_LI_EDIT, BASE_MVC, _l ){
/* global Backbone */
'use strict';
//==============================================================================
var DCListItemView = DC_LI.DCListItemView;
/** @class Edit view for DatasetCollection.
@@ -4,7 +4,8 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( LIST_ITEM, DATASET_LI, BASE_MVC, _l ){
/* global Backbone */
'use strict';
//==============================================================================
var FoldoutListItemView = LIST_ITEM.FoldoutListItemView,
ListItemView = LIST_ITEM.ListItemView;
@@ -33,11 +34,11 @@ var DCListItemView = FoldoutListItemView.extend(
_setUpListeners : function(){
FoldoutListItemView.prototype._setUpListeners.call( this );
// re-rendering on deletion
this.model.on( 'change', function( model, options ){
this.listenTo( this.model, 'change', function( model, options ){
if( _.isEqual( _.keys( model.changed ), [ 'deleted' ] ) ){
this.render();
}
}, this );
});
},
// ......................................................................... rendering
@@ -4,6 +4,8 @@ define([
"utils/localization"
], function( DATASET_MODEL, BASE_MVC, _l ){
'use strict';
var logNamespace = 'collections';
//==============================================================================
/*
@@ -133,14 +135,13 @@ var DatasetDCE = DATASET_MODEL.DatasetAssociation.extend( BASE_MVC.mixin( Datase
/** url fn */
url : function(){
var galaxyRoot = (( window.galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' ));
// won't always be an hda
if( !this.has( 'history_id' ) ){
console.warn( 'no endpoint for non-hdas within a collection yet' );
// (a little silly since this api endpoint *also* points at hdas)
return galaxyRoot + 'api/datasets';
return Galaxy.root + 'api/datasets';
}
return galaxyRoot + 'api/histories/' + this.get( 'history_id' ) + '/contents/' + this.get( 'id' );
return Galaxy.root + 'api/histories/' + this.get( 'history_id' ) + '/contents/' + this.get( 'id' );
},
defaults : _.extend( {},
@@ -1,19 +1,22 @@
define([
"mvc/collection/collection-panel",
"mvc/collection/collection-view",
"mvc/collection/collection-model",
"mvc/collection/collection-li-edit",
"mvc/base-mvc",
"utils/localization"
], function( DC_PANEL, DC_MODEL, DC_EDIT, BASE_MVC, _l ){
"utils/localization",
"ui/editable-text",
], function( DC_VIEW, DC_MODEL, DC_EDIT, BASE_MVC, _l ){
'use strict';
/* =============================================================================
TODO:
============================================================================= */
/** @class editable View/Controller for a dataset collection.
*/
var _super = DC_PANEL.CollectionPanel;
var CollectionPanelEdit = _super.extend(
/** @lends CollectionPanel.prototype */{
var _super = DC_VIEW.CollectionView;
var CollectionViewEdit = _super.extend(
/** @lends CollectionView.prototype */{
//MODEL is either a DatasetCollection (or subclass) or a DatasetCollectionElement (list of pairs)
/** logger used to record this.log messages, commonly set to console */
@@ -40,7 +43,7 @@ var CollectionPanelEdit = _super.extend(
if( !this.model ){ return; }
// anon users shouldn't have access to any of the following
if( !Galaxy.currUser || Galaxy.currUser.isAnonymous() ){
if( !Galaxy.user || Galaxy.user.isAnonymous() ){
return;
}
@@ -69,37 +72,37 @@ var CollectionPanelEdit = _super.extend(
// ........................................................................ misc
/** string rep */
toString : function(){
return 'CollectionPanelEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'CollectionViewEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
// =============================================================================
/** @class non-editable, read-only View/Controller for a dataset collection. */
var ListCollectionPanelEdit = CollectionPanelEdit.extend(
/** @lends ListCollectionPanel.prototype */{
var ListCollectionViewEdit = CollectionViewEdit.extend(
/** @lends ListCollectionView.prototype */{
//TODO: not strictly needed - due to switch in CollectionPanel._getContentClass
//TODO: not strictly needed - due to switch in CollectionView._getContentClass
/** sub view class used for datasets */
DatasetDCEViewClass : DC_EDIT.DatasetDCEListItemEdit,
// ........................................................................ misc
/** string rep */
toString : function(){
return 'ListCollectionPanelEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'ListCollectionViewEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
// =============================================================================
/** @class Editable, read-only View/Controller for a dataset collection. */
var PairCollectionPanelEdit = ListCollectionPanelEdit.extend(
/** @lends PairCollectionPanelEdit.prototype */{
var PairCollectionViewEdit = ListCollectionViewEdit.extend(
/** @lends PairCollectionViewEdit.prototype */{
// ........................................................................ misc
/** string rep */
toString : function(){
return 'PairCollectionPanelEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'PairCollectionViewEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
@@ -108,8 +111,8 @@ var PairCollectionPanelEdit = ListCollectionPanelEdit.extend(
/** @class Editable (roughly since these collections are immutable),
* View/Controller for a dataset collection.
*/
var NestedPairCollectionPanelEdit = PairCollectionPanelEdit.extend(
/** @lends NestedPairCollectionPanelEdit.prototype */{
var NestedPairCollectionViewEdit = PairCollectionViewEdit.extend(
/** @lends NestedPairCollectionViewEdit.prototype */{
/** Override to remove the editable text from the name/identifier - these collections are considered immutable */
_setUpBehaviors : function( $where ){
@@ -119,35 +122,35 @@ var NestedPairCollectionPanelEdit = PairCollectionPanelEdit.extend(
// ........................................................................ misc
/** string rep */
toString : function(){
return 'NestedPairCollectionPanelEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'NestedPairCollectionViewEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
// =============================================================================
/** @class non-editable, read-only View/Controller for a dataset collection. */
var ListOfPairsCollectionPanelEdit = CollectionPanelEdit.extend(
/** @lends ListOfPairsCollectionPanel.prototype */{
var ListOfPairsCollectionViewEdit = CollectionViewEdit.extend(
/** @lends ListOfPairsCollectionView.prototype */{
//TODO: not strictly needed - due to switch in CollectionPanel._getContentClass
//TODO: not strictly needed - due to switch in CollectionView._getContentClass
/** sub view class used for nested collections */
NestedDCDCEViewClass : DC_EDIT.NestedDCDCEListItemEdit.extend({
foldoutPanelClass : NestedPairCollectionPanelEdit
foldoutPanelClass : NestedPairCollectionViewEdit
}),
// ........................................................................ misc
/** string rep */
toString : function(){
return 'ListOfPairsCollectionPanelEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'ListOfPairsCollectionViewEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
//==============================================================================
return {
CollectionPanelEdit : CollectionPanelEdit,
ListCollectionPanelEdit : ListCollectionPanelEdit,
PairCollectionPanelEdit : PairCollectionPanelEdit,
ListOfPairsCollectionPanelEdit : ListOfPairsCollectionPanelEdit
CollectionViewEdit : CollectionViewEdit,
ListCollectionViewEdit : ListCollectionViewEdit,
PairCollectionViewEdit : PairCollectionViewEdit,
ListOfPairsCollectionViewEdit : ListOfPairsCollectionViewEdit
};
});
@@ -1,10 +1,12 @@
define([
"mvc/list/list-panel",
"mvc/list/list-view",
"mvc/collection/collection-model",
"mvc/collection/collection-li",
"mvc/base-mvc",
"utils/localization"
], function( LIST_PANEL, DC_MODEL, DC_LI, BASE_MVC, _l ){
], function( LIST_VIEW, DC_MODEL, DC_LI, BASE_MVC, _l ){
'use strict';
var logNamespace = 'collections';
/* =============================================================================
@@ -13,9 +15,9 @@ TODO:
============================================================================= */
/** @class non-editable, read-only View/Controller for a dataset collection.
*/
var _super = LIST_PANEL.ModelListPanel;
var CollectionPanel = _super.extend(
/** @lends CollectionPanel.prototype */{
var _super = LIST_VIEW.ModelListPanel;
var CollectionView = _super.extend(
/** @lends CollectionView.prototype */{
//MODEL is either a DatasetCollection (or subclass) or a DatasetCollectionElement (list of pairs)
_logNamespace : logNamespace,
@@ -83,12 +85,14 @@ var CollectionPanel = _super.extend(
_super.prototype._setUpItemViewListeners.call( panel, view );
// use pub-sub to: handle drilldown expansion and collapse
view.on( 'expanded:drilldown', function( v, drilldown ){
this._expandDrilldownPanel( drilldown );
}, this );
view.on( 'collapsed:drilldown', function( v, drilldown ){
this._collapseDrilldownPanel( drilldown );
}, this );
panel.listenTo( view, {
'expanded:drilldown': function( v, drilldown ){
this._expandDrilldownPanel( drilldown );
},
'collapsed:drilldown': function( v, drilldown ){
this._collapseDrilldownPanel( drilldown );
}
});
return this;
},
@@ -122,13 +126,13 @@ var CollectionPanel = _super.extend(
// ........................................................................ misc
/** string rep */
toString : function(){
return 'CollectionPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'CollectionView(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
//------------------------------------------------------------------------------ TEMPLATES
CollectionPanel.prototype.templates = (function(){
CollectionView.prototype.templates = (function(){
var controlsTemplate = BASE_MVC.wrapTemplate([
'<div class="controls">',
@@ -164,58 +168,58 @@ CollectionPanel.prototype.templates = (function(){
// =============================================================================
/** @class non-editable, read-only View/Controller for a dataset collection. */
var ListCollectionPanel = CollectionPanel.extend(
/** @lends ListCollectionPanel.prototype */{
var ListCollectionView = CollectionView.extend(
/** @lends ListCollectionView.prototype */{
//TODO: not strictly needed - due to switch in CollectionPanel._getContentClass
//TODO: not strictly needed - due to switch in CollectionView._getContentClass
/** sub view class used for datasets */
DatasetDCEViewClass : DC_LI.DatasetDCEListItemView,
// ........................................................................ misc
/** string rep */
toString : function(){
return 'ListCollectionPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'ListCollectionView(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
// =============================================================================
/** @class non-editable, read-only View/Controller for a dataset collection. */
var PairCollectionPanel = ListCollectionPanel.extend(
/** @lends PairCollectionPanel.prototype */{
var PairCollectionView = ListCollectionView.extend(
/** @lends PairCollectionView.prototype */{
// ........................................................................ misc
/** string rep */
toString : function(){
return 'PairCollectionPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'PairCollectionView(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
// =============================================================================
/** @class non-editable, read-only View/Controller for a dataset collection. */
var ListOfPairsCollectionPanel = CollectionPanel.extend(
/** @lends ListOfPairsCollectionPanel.prototype */{
var ListOfPairsCollectionView = CollectionView.extend(
/** @lends ListOfPairsCollectionView.prototype */{
//TODO: not strictly needed - due to switch in CollectionPanel._getContentClass
//TODO: not strictly needed - due to switch in CollectionView._getContentClass
/** sub view class used for nested collections */
NestedDCDCEViewClass : DC_LI.NestedDCDCEListItemView.extend({
foldoutPanelClass : PairCollectionPanel
foldoutPanelClass : PairCollectionView
}),
// ........................................................................ misc
/** string rep */
toString : function(){
return 'ListOfPairsCollectionPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'ListOfPairsCollectionView(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
//==============================================================================
return {
CollectionPanel : CollectionPanel,
ListCollectionPanel : ListCollectionPanel,
PairCollectionPanel : PairCollectionPanel,
ListOfPairsCollectionPanel : ListOfPairsCollectionPanel
CollectionView : CollectionView,
ListCollectionView : ListCollectionView,
PairCollectionView : PairCollectionView,
ListOfPairsCollectionView : ListOfPairsCollectionView
};
});
@@ -9,6 +9,8 @@ define([
"ui/hoverhighlight"
], function( HDCA, STATES, BASE_MVC, UI_MODAL, naturalSort, _l ){
'use strict';
var logNamespace = 'collections';
/*==============================================================================
TODO:
@@ -1008,7 +1010,7 @@ var collectionCreatorModal = function _collectionCreatorModal( elements, options
title : options.title || _l( 'Create a collection' ),
body : creator.$el,
width : '80%',
height : 'min-content',
height : '100%',
closing_events: true
});
creator.render();
@@ -7,6 +7,8 @@ define([
"ui/hoverhighlight"
], function( levenshteinDistance, naturalSort, LIST_COLLECTION_CREATOR, baseMVC, _l ){
'use strict';
var logNamespace = 'collections';
/* ============================================================================
TODO:
@@ -90,13 +92,14 @@ var PairView = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
function autoPairFnBuilder( options ){
options = options || {};
options.createPair = options.createPair || function _defaultCreatePair( params ){
this.debug( 'creating pair:', params.listA[ params.indexA ].name, params.listB[ params.indexB ].name );
params = params || {};
return this._pair(
params.listA.splice( params.indexA, 1 )[0],
params.listB.splice( params.indexB, 1 )[0],
{ silent: true }
);
var a = params.listA.splice( params.indexA, 1 )[0],
b = params.listB.splice( params.indexB, 1 )[0],
aInBIndex = params.listB.indexOf( a ),
bInAIndex = params.listA.indexOf( b );
if( aInBIndex !== -1 ){ params.listB.splice( aInBIndex, 1 ); }
if( bInAIndex !== -1 ){ params.listA.splice( bInAIndex, 1 ); }
return this._pair( a, b, { silent: true });
};
// compile these here outside of the loop
var _regexps = [];
@@ -162,14 +165,14 @@ function autoPairFnBuilder( options ){
this.debug( 'bestMatch.score:', bestMatch.score );
if( bestMatch.score >= scoreThreshold ){
this.debug( 'creating pair' );
//console.debug( 'autoPairFnBuilder.strategy', listA[ indexA ].name, listB[ bestMatch.index ].name );
paired.push( options.createPair.call( this, {
listA : listA,
indexA : indexA,
listB : listB,
indexB : bestMatch.index
}));
this.debug( 'list lens now:', listA.length, listB.length );
//console.debug( 'list lens now:', listA.length, listB.length );
} else {
indexA += 1;
}
@@ -480,7 +483,7 @@ var PairedCollectionCreator = Backbone.View.extend( baseMVC.LoggableMixin ).exte
/** create a pair from fwd and rev, removing them from unpaired, and placing the new pair in paired */
_pair : function( fwd, rev, options ){
options = options || {};
//this.debug( '_pair:', fwd, rev );
this.debug( '_pair:', fwd, rev );
var pair = this._createPair( fwd, rev, options.name );
this.paired.push( pair );
this.unpaired = _.without( this.unpaired, fwd, rev );
@@ -572,8 +575,7 @@ var PairedCollectionCreator = Backbone.View.extend( baseMVC.LoggableMixin ).exte
*/
createList : function( name ){
var creator = this,
root = ( window.Galaxy && Galaxy.options.root )? Galaxy.options.root : '/',
url = root + 'api/histories/' + this.historyId + '/contents/dataset_collections';
url = Galaxy.root + 'api/histories/' + this.historyId + '/contents/dataset_collections';
//TODO: use ListPairedCollection.create()
var ajaxData = {
@@ -921,7 +923,11 @@ var PairedCollectionCreator = Backbone.View.extend( baseMVC.LoggableMixin ).exte
this.$( '.collection-name' ).focus();
}
} else {
message = _l( 'Could not automatically create any pairs from the given dataset names' );
message = _l([
'Could not automatically create any pairs from the given dataset names.',
'You may want to choose or enter different filters and try auto-pairing again.',
'Close this message using the X on the right to view more help.'
].join( ' ' ));
}
this._showAlert( message, msgClass );
});
@@ -5,6 +5,8 @@ define([
"utils/localization"
], function( LIST_CREATOR, HDCA, BASE_MVC, _l ){
'use strict';
var logNamespace = 'collections';
/*==============================================================================
TODO:
@@ -54,7 +54,7 @@ var Dataset = Backbone.Model.extend({
return this.attributes.metadata.get(attribute);
},
urlRoot: galaxy_config.root + "api/datasets"
urlRoot: Galaxy.root + "api/datasets"
});
/**
@@ -73,8 +73,8 @@ var TabularDataset = Dataset.extend({
// If first data chunk is available, next chunk is 1.
this.attributes.chunk_index = (this.attributes.first_data_chunk ? 1 : 0);
this.attributes.chunk_url = galaxy_config.root + 'dataset/display?dataset_id=' + this.id;
this.attributes.url_viz = galaxy_config.root + 'visualization';
this.attributes.chunk_url = Galaxy.root + 'dataset/display?dataset_id=' + this.id;
this.attributes.url_viz = Galaxy.root + 'visualization';
},
/**
@@ -5,6 +5,7 @@ define([
'mvc/base-mvc',
'utils/localization'
], function( DATASET, DATASET_LIST, MODAL, BASE_MVC, _l ){
'use strict';
var logNamespace = 'dataset';
/* ============================================================================
@@ -21,20 +22,6 @@ TODO:
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.
*/
@@ -1,13 +1,14 @@
define([
"mvc/dataset/states",
"mvc/dataset/dataset-li",
"mvc/tags",
"mvc/annotations",
"mvc/tag",
"mvc/annotation",
"ui/fa-icon-button",
"mvc/base-mvc",
"mvc/tools/tools-form",
"utils/localization"
], function( STATES, DATASET_LI, TAGS, ANNOTATIONS, faIconButton, BASE_MVC, ToolsForm, _l ){
], function( STATES, DATASET_LI, TAGS, ANNOTATIONS, faIconButton, BASE_MVC, _l ){
'use strict';
//==============================================================================
var _super = DATASET_LI.DatasetListItemView;
/** @class Editing view for DatasetAssociation.
@@ -158,19 +159,23 @@ var DatasetListItemEdit = _super.extend(
/** Render icon-button to re-run the job that created this dataset. */
_renderRerunButton : function(){
var creating_job = this.model.get('creating_job');
if (this.model.get('rerunnable')){
var creating_job = this.model.get( 'creating_job' );
if( this.model.get( 'rerunnable' ) ){
return faIconButton({
title : _l( 'Run this job again' ),
href : this.model.urls.rerun,
classes : 'rerun-btn',
target : this.linkTarget,
faIcon : 'fa-refresh',
onclick : function(ev) {
onclick : function( ev ) {
ev.preventDefault();
var form = new ToolsForm.View({'job_id' : creating_job});
form.deferred.execute(function(){
Galaxy.app.display(form);
// create webpack split point in order to load the tool form async
// TODO: split not working (tool loads fine)
require([ 'mvc/tool/tool-form' ], function( ToolForm ){
var form = new ToolForm.View({ 'job_id' : creating_job });
form.deferred.execute( function(){
Galaxy.app.display( form );
});
});
}
});
@@ -206,9 +211,8 @@ var DatasetListItemEdit = _super.extend(
$links.click( function( ev ){
if( Galaxy.frame && Galaxy.frame.active ){
Galaxy.frame.add({
title : "Visualization",
type : "url",
content : $( this ).attr( 'href' )
title : 'Visualization',
url : $( this ).attr( 'href' )
});
ev.preventDefault();
ev.stopPropagation();
@@ -5,7 +5,7 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( LIST_ITEM, STATES, faIconButton, BASE_MVC, _l ){
/* global Backbone */
'use strict';
var logNamespace = 'dataset';
/*==============================================================================
@@ -44,7 +44,7 @@ var DatasetListItemView = _super.extend(
_super.prototype._setUpListeners.call( this );
// re-rendering on any model changes
this.model.on( 'change', function( model, options ){
this.listenTo( this.model, 'change', function( model, options ){
// if the model moved into the ready state and is expanded without details, fetch those details now
if( this.model.changedAttributes().state && this.model.inReadyState()
&& this.expanded && !this.model.hasDetails() ){
@@ -54,7 +54,7 @@ var DatasetListItemView = _super.extend(
} else {
this.render();
}
}, this );
});
},
// ......................................................................... expandable
@@ -161,7 +161,7 @@ var DatasetListItemView = _super.extend(
displayBtnData.onclick = function( ev ){
if (Galaxy.frame && Galaxy.frame.active) {
// Add dataset to frames.
Galaxy.frame.add_dataset(self.model.get('id'));
Galaxy.frame.addDataset(self.model.get('id'));
ev.preventDefault();
}
};
@@ -267,7 +267,7 @@ var DatasetListItemView = _super.extend(
}
return $([
'<a class="download-btn icon-btn" href="', this.model.urls.download, '" title="' + _l( 'Download' ) + '">',
'<a class="download-btn icon-btn" href="', this.model.urls.download, '" title="' + _l( 'Download' ) + '" download>',
'<span class="fa fa-floppy-o"></span>',
'</a>'
].join( '' ));
@@ -283,7 +283,7 @@ var DatasetListItemView = _super.extend(
'<span class="fa fa-floppy-o"></span>',
'</a>',
'<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">',
'<li><a href="' + urls.download + '">', _l( 'Download dataset' ), '</a></li>',
'<li><a href="' + urls.download + '" download>', _l( 'Download dataset' ), '</a></li>',
_.map( this.model.get( 'meta_files' ), function( meta_file ){
return [
'<li><a href="', urls.meta_download + meta_file.file_type, '">',
@@ -1,16 +1,17 @@
define([
"mvc/list/list-panel",
"mvc/list/list-view",
"mvc/dataset/dataset-li",
"mvc/base-mvc",
"utils/localization"
], function( LIST_PANEL, DATASET_LI, BASE_MVC, _l ){
], function( LIST_VIEW, DATASET_LI, BASE_MVC, _l ){
'use strict';
var logNamespace = 'dataset';
/* =============================================================================
TODO:
============================================================================= */
var _super = LIST_PANEL.ListPanel;
var _super = LIST_VIEW.ListPanel;
/** @class non-editable, read-only View/Controller for a list of datasets.
*/
var DatasetList = _super.extend(
@@ -3,6 +3,7 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( STATES, BASE_MVC, _l ){
'use strict';
var logNamespace = 'dataset';
//==============================================================================
@@ -79,9 +80,8 @@ var DatasetAssociation = Backbone.Model
'meta_download' : 'dataset/get_metadata_file?hda_id=' + id + '&metadata_name='
};
//TODO: global
var root = ( window.galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' );
_.each( urls, function( value, key ){
urls[ key ] = root + value;
urls[ key ] = Galaxy.root + value;
});
this.urls = urls;
return urls;
@@ -251,12 +251,11 @@ var DatasetAssociationCollection = Backbone.Collection.extend( BASE_MVC.Loggable
model : DatasetAssociation,
/** root api url */
urlRoot : (( window.galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' ))
+ 'api/datasets',
urlRoot : Galaxy.root + 'api/datasets',
/** url fn */
url : function(){
return this.urlRoot
return this.urlRoot;
},
// ........................................................................ common queries
@@ -1,5 +1,7 @@
define([
], function(){
'use strict';
//==============================================================================
/** Map of possible HDA/collection/job states to their string equivalents.
* A port of galaxy.model.Dataset.states.
+216 -255
View File
@@ -1,295 +1,256 @@
/*
This class maps the form dom to an api compatible javascript dictionary.
*/
define(['utils/utils'], function(Utils) {
return Backbone.Model.extend({
// initialize
initialize: function(app) {
this.app = app;
},
define([ 'utils/utils' ], function( Utils ) {
var Manager = Backbone.Model.extend({
initialize: function( app ) {
this.app = app;
},
/** Creates a checksum.
*/
checksum: function() {
var sum = '';
var self = this;
this.app.section.$el.find('.section-row').each(function() {
var id = $(this).attr('id');
var field = self.app.field_list[id];
if (field) {
sum += id + ':' + JSON.stringify(field.value && field.value()) + ':' + field.collapsed + ';';
/** Creates a checksum.
*/
checksum: function() {
var sum = '';
var self = this;
this.app.section.$el.find( '.section-row' ).each( function() {
var id = $(this).attr( 'id' );
var field = self.app.field_list[ id ];
if ( field ) {
sum += id + ':' + JSON.stringify( field.value && field.value() ) + ':' + field.collapsed + ';';
}
});
return sum;
},
/** Convert dom into a dictionary of flat id/value pairs used e.g. on job submission.
*/
create: function() {
var self = this;
// get raw dictionary from dom
var dict = {};
this._iterate( this.app.section.$el, dict );
// add to result dictionary, label elements
var result_dict = {};
this.flat_dict = {};
function add( flat_id, input_id, input_value ) {
self.flat_dict[ flat_id ] = input_id;
result_dict[ flat_id ] = input_value;
self.app.element_list[ input_id ] && self.app.element_list[ input_id ].$el.attr( 'tour_id', flat_id );
}
});
return sum;
},
/** Convert dom into dictionary.
*/
create: function() {
// link this
var self = this;
// get raw dictionary from dom
var dict = {};
this._iterate(this.app.section.$el, dict);
// add to result dictionary
var result_dict = {};
this.map_dict = {};
function add(job_input_id, input_id, input_value) {
self.map_dict[job_input_id] = input_id;
result_dict[job_input_id] = input_value;
};
// converter between raw dictionary and job dictionary
function convert(identifier, head) {
for (var index in head) {
var node = head[index];
if (node.input) {
// get node
var input = node.input;
// create identifier
var job_input_id = identifier;
if (identifier != '') {
job_input_id += '|';
}
job_input_id += input.name;
// process input type
switch (input.type) {
// handle repeats
case 'repeat':
// section identifier
var section_label = 'section-';
// collect repeat block identifiers
var block_indices = [];
var block_prefix = null;
for (var block_label in node) {
var pos = block_label.indexOf(section_label);
if (pos != -1) {
pos += section_label.length;
block_indices.push(parseInt(block_label.substr(pos)));
if (!block_prefix) {
block_prefix = block_label.substr(0, pos);
}
}
}
// sort repeat blocks
block_indices.sort(function(a,b) { return a - b; });
// add to response dictionary in created order
var index = 0;
for (var i in block_indices) {
convert(job_input_id + '_' + index++, node[block_prefix + block_indices[i]]);
}
break;
// handle conditionals
case 'conditional':
// get conditional value
var value = self.app.field_list[input.id].value();
// add conditional value
add (job_input_id + '|' + input.test_param.name, input.id, value);
// identify selected case
var selectedCase = self.matchCase(input, value);
if (selectedCase != -1) {
convert(job_input_id, head[input.id + '-section-' + selectedCase]);
}
break;
// handle sections
case 'section':
convert(!input.flat && job_input_id || '', node);
break;
default:
// get field
var field = self.app.field_list[input.id];
if (field && field.value) {
// validate field value
var value = field.value();
// ignore certain values
if (input.ignore === undefined || input.ignore != value) {
// replace value by collapsible value
if (field.collapsed && input.collapsible_value) {
value = input.collapsible_value;
}
// add value to submission
add (job_input_id, input.id, value);
// add payload to submission
if (input.payload) {
for (var p_id in input.payload) {
add (p_id, input.id, input.payload[p_id]);
// converter between raw dictionary and job dictionary
function convert( identifier, head ) {
for ( var index in head ) {
var node = head[ index ];
if ( node.input ) {
var input = node.input;
var flat_id = identifier;
if ( identifier != '' ) {
flat_id += '|';
}
flat_id += input.name;
switch ( input.type ) {
case 'repeat':
var section_label = 'section-';
var block_indices = [];
var block_prefix = null;
for ( var block_label in node ) {
var pos = block_label.indexOf( section_label );
if ( pos != -1 ) {
pos += section_label.length;
block_indices.push( parseInt( block_label.substr( pos ) ));
if ( !block_prefix ) {
block_prefix = block_label.substr( 0, pos );
}
}
}
}
block_indices.sort( function( a, b ) { return a - b; });
var index = 0;
for ( var i in block_indices ) {
convert( flat_id + '_' + index++, node[ block_prefix + block_indices[ i ] ]);
}
break;
case 'conditional':
var value = self.app.field_list[ input.id ].value();
add( flat_id + '|' + input.test_param.name, input.id, value );
var selectedCase = matchCase( input, value );
if ( selectedCase != -1 ) {
convert( flat_id, head[ input.id + '-section-' + selectedCase ] );
}
break;
case 'section':
convert( !input.flat && flat_id || '', node );
break;
default:
var field = self.app.field_list[ input.id ];
if ( field && field.value ) {
var value = field.value();
if ( input.ignore === undefined || input.ignore != value ) {
if ( field.collapsed && input.collapsible_value ) {
value = input.collapsible_value;
}
add( flat_id, input.id, value );
if ( input.payload ) {
for ( var p_id in input.payload ) {
add( p_id, input.id, input.payload[ p_id ] );
}
}
}
}
}
}
}
}
convert( '', dict );
return result_dict;
},
/** Matches flat ids to corresponding input element
* @param{string} flat_id - Flat input id to be looked up.
*/
match: function ( flat_id ) {
return this.flat_dict && this.flat_dict[ flat_id ];
},
/** Match conditional values to selected cases
*/
matchCase: function( input, value ) {
return matchCase( input, value );
},
/** Matches a new tool model to the current input elements e.g. used to update dynamic options
*/
matchModel: function( model, callback ) {
return matchIds( model.inputs, this.flat_dict, callback );
},
/** Matches identifier from api response to input elements e.g. used to display validation errors
*/
matchResponse: function( response ) {
var result = {};
var self = this;
function search ( id, head ) {
if ( typeof head === 'string' ) {
var input_id = self.flat_dict[ id ];
input_id && ( result[ input_id ] = head );
} else {
for ( var i in head ) {
var new_id = i;
if ( id !== '' ) {
var separator = '|';
if ( head instanceof Array ) {
separator = '_';
}
new_id = id + separator + new_id;
}
search ( new_id, head[ i ] );
}
}
}
search( '', response );
return result;
},
/** Map dom tree to dictionary tree with input elements.
*/
_iterate: function( parent, dict ) {
var self = this;
var children = $( parent ).children();
children.each( function() {
var child = this;
var id = $( child ).attr( 'id' );
if ( $( child ).hasClass( 'section-row' ) ) {
var input = self.app.input_list[ id ];
dict[ id ] = ( input && { input : input } ) || {};
self._iterate( child, dict[ id ] );
} else {
self._iterate( child, dict );
}
});
}
// start conversion
convert('', dict);
// return result
return result_dict;
},
/** Match job definition identifier to input element identifier
*/
match: function (job_input_id) {
return this.map_dict && this.map_dict[job_input_id];
},
});
/** Match conditional values to selected cases
*/
matchCase: function(input, value) {
// format value for boolean inputs
if (input.test_param.type == 'boolean') {
if (value == 'true') {
* @param{dict} input - Definition of conditional input parameter
* @param{dict} value - Current value
*/
var matchCase = function( input, value ) {
if ( input.test_param.type == 'boolean' ) {
if ( value == 'true' ) {
value = input.test_param.truevalue || 'true';
} else {
value = input.test_param.falsevalue || 'false';
}
}
// find selected case
for (var i in input.cases) {
if (input.cases[i].value == value) {
for ( var i in input.cases ) {
if ( input.cases[ i ].value == value ) {
return i;
}
}
// selected case not found
return -1;
},
};
/** Matches identifier from api model to input elements
*/
matchModel: function(model, callback) {
// final result dictionary
var result = {};
// link this
var self = this;
// search throughout response
function search (id, head) {
for (var i in head) {
var node = head[i];
var index = node.name;
if (id != '') {
index = id + '|' + index;
/** Match context
* @param{dict} inputs - Dictionary of input elements
* @param{dict} key - Reference key which is matched to an input name e.g. data_ref
* @param{dict} callback - Called with matched context i.e. callback( input, referenced_input )
*/
var matchContext = function( inputs, key, callback, context ) {
context = $.extend( true, {}, context );
_.each( inputs, function ( input ) {
input && input.type && ( context[ input.name ] = input );
});
_.each( inputs, function ( input ) {
if ( _.isObject( input ) ) {
if ( input.type && context[ input[ key ] ] ) {
callback ( input, context[ input[ key ] ] );
} else {
matchContext( input, key, callback, context );
}
switch (node.type) {
}
});
};
/** Matches a tool model to a dictionary, indexed with flat ids
* @param{dict} inputs - Dictionary of input elements
* @param{dict} mapping - Dictionary containing flat ids
* @param{dict} callback - Called with the mapped dictionary object and corresponding model node
*/
var matchIds = function( inputs, mapping, callback ) {
var result = {};
var self = this;
function search ( id, head ) {
for ( var i in head ) {
var node = head[ i ];
var index = node.name;
id != '' && ( index = id + '|' + index );
switch ( node.type ) {
case 'repeat':
for (var j in node.cache) {
search (index + '_' + j, node.cache[j]);
for ( var j in node.cache ) {
search ( index + '_' + j, node.cache[ j ] );
}
break;
case 'conditional':
var value = node.test_param && node.test_param.value;
var selectedCase = self.matchCase(node, value);
if (selectedCase != -1) {
search (index, node.cases[selectedCase].inputs);
}
var selectedCase = matchCase( node, node.test_param && node.test_param.value );
selectedCase != -1 && search ( index, node.cases[ selectedCase ].inputs );
break;
case 'section':
search (index, node.inputs);
search ( index, node.inputs );
break;
default:
var input_id = self.map_dict[index];
if (input_id) {
callback(input_id, node);
}
var mapped = mapping[ index ];
mapped && callback( mapped, node );
}
}
}
// match all ids and return messages
search('', model.inputs);
// return matched results
search( '', inputs );
return result;
},
};
/** Matches identifier from api response to input elements
*/
matchResponse: function(response) {
// final result dictionary
var result = {};
// link this
var self = this;
// search throughout response
function search (id, head) {
if (typeof head === 'string') {
var input_id = self.map_dict[id];
if (input_id) {
result[input_id] = head;
}
} else {
for (var i in head) {
var new_id = i;
if (id !== '') {
var separator = '|';
if (head instanceof Array) {
separator = '_';
}
new_id = id + separator + new_id;
}
search (new_id, head[i]);
}
}
}
// match all ids and return messages
search('', response);
// return matched results
return result;
},
/** Iterate through the form dom and map it to the dictionary.
*/
_iterate: function(parent, dict) {
// get child nodes
var self = this;
var children = $(parent).children();
children.each(function() {
// get child element
var child = this;
// get id
var id = $(child).attr('id');
// create new branch
if ($(child).hasClass('section-row')) {
// create sub dictionary
dict[id] = {};
// add input element if it exists
var input = self.app.input_list[id];
if (input) {
dict[id] = {
input : input
}
}
// fill sub dictionary
self._iterate(child, dict[id]);
} else {
self._iterate(child, dict);
}
});
return {
Manager : Manager,
matchIds : matchIds,
matchContext : matchContext
}
});
});
+46 -50
View File
@@ -4,53 +4,51 @@
define([], function() {
return Backbone.View.extend({
initialize: function(app, options) {
// link app
this.app = app;
this.field = options.field;
// set text labels and icons for optional button
// set text labels and icons for collapsible button
this.text_enable = app.options.text_enable || 'Enable';
this.text_disable = app.options.text_disable || 'Disable';
this.cls_enable = app.options.cls_enable || 'fa fa-caret-square-o-down';
this.cls_disable = app.options.cls_disable || 'fa fa-caret-square-o-up';
// link field
this.field = options.field;
this.default_value = options.default_value;
// set element
this.setElement(this._template(options));
// link elements
this.$field = this.$el.find('.ui-table-form-field');
this.$optional = this.$el.find('.ui-table-form-optional');
this.$optional_icon = this.$el.find('.ui-table-form-optional').find('.icon');
this.$error_text = this.$el.find('.ui-table-form-error-text');
this.$error = this.$el.find('.ui-table-form-error');
this.$field = this.$('.ui-form-field');
this.$preview = this.$('.ui-form-preview');
this.$collapsible = this.$('.ui-form-collapsible');
this.$collapsible_icon = this.$('.ui-form-collapsible').find('.icon');
this.$error_text = this.$('.ui-form-error-text');
this.$error = this.$('.ui-form-error');
this.$backdrop = this.$('.ui-form-backdrop');
// add field element
this.$field.prepend(this.field.$el);
// decide wether to expand or collapse optional fields
this.field.collapsed = options.collapsible && options.value &&
JSON.stringify(options.value) == JSON.stringify(options.collapsible_value);
// decide wether to expand or collapse fields
this.field.collapsed = options.collapsible_value !== undefined && JSON.stringify( options.value ) == JSON.stringify( options.collapsible_value );
// refresh view
this._refresh();
// add optional hide/show
// add collapsible hide/show
var self = this;
this.$optional.on('click', function() {
// flip flag
this.$collapsible.on('click', function() {
self.field.collapsed = !self.field.collapsed;
// refresh view
self._refresh();
// refresh state
self.app.trigger('change');
});
},
/** Disable input element
*/
disable: function( silent ) {
this.$backdrop.show();
silent && this.$backdrop.css({ 'opacity': 0, 'cursor': 'default' } );
},
/** Set error text
*/
error: function(text) {
@@ -69,61 +67,59 @@ define([], function() {
/** Refresh element
*/
_refresh: function() {
// reset optional button
this.$optional_icon.removeClass().addClass('icon');
// identify state
this.$collapsible_icon.removeClass().addClass('icon');
if (!this.field.collapsed) {
// enable input field
this.$field.fadeIn('fast');
this.$preview.hide();
this._tooltip(this.text_disable, this.cls_disable);
this.app.trigger('change');
} else {
// disable input field
this.$field.hide();
this.$preview.show();
this._tooltip(this.text_enable, this.cls_enable);
this.field.value && this.field.value(this.default_value);
}
this.app.trigger('change');
},
/** Set tooltip text
*/
_tooltip: function(title, cls) {
if (this.$optional.length) {
this.$optional_icon.addClass(cls)
.tooltip({ placement: 'bottom' })
.attr('data-original-title', title)
.tooltip('fixTitle').tooltip('hide');
}
this.$collapsible_icon.addClass(cls)
.tooltip({ placement: 'bottom' })
.attr('data-original-title', title)
.tooltip('fixTitle').tooltip('hide');
},
/** Main Template
*/
_template: function(options) {
var tmp = '<div class="ui-table-form-element input-name-' + options.name + '">' +
'<div class="ui-table-form-error ui-error">' +
'<span class="fa fa-arrow-down"/><span class="ui-table-form-error-text"/>' +
var tmp = '<div class="ui-form-element">' +
'<div class="ui-form-error ui-error">' +
'<span class="fa fa-arrow-down"/><span class="ui-form-error-text"/>' +
'</div>' +
'<div class="ui-table-form-title">';
if (options.collapsible) {
tmp += '<div class="ui-table-form-optional">' +
'<div class="ui-form-title">';
if ( !options.disabled && options.collapsible_value !== undefined ) {
tmp += '<div class="ui-form-collapsible">' +
'<i class="icon"/>' + options.label +
'</div>';
} else {
tmp += options.label;
}
tmp += '</div>' +
'<div class="ui-table-form-field">';
tmp += '<div class="ui-table-form-info">';
'<div class="ui-form-field">';
tmp += '<div class="ui-form-info">';
if (options.help) {
tmp += options.help;
if (options.argument && options.help.indexOf('(' + options.argument + ')') == -1) {
tmp += ' (' + options.argument + ')';
}
}
tmp += '</div>';
tmp += '</div>' +
'</div>';
if (options.argument && options.help.indexOf('(' + options.argument + ')') == -1) {
tmp += ' (' + options.argument + ')';
}
tmp += '</div>' +
'<div class="ui-form-backdrop"/>' +
'</div>';
if ( options.collapsible_preview ) {
tmp += '<div class="ui-form-preview">' + options.text_value + '</div>';
}
tmp += '</div>';
return tmp;
}
});
@@ -7,7 +7,7 @@ define(['utils/utils',
'mvc/ui/ui-select-library',
'mvc/ui/ui-select-ftp',
'mvc/ui/ui-color-picker'],
function(Utils, Ui, SelectContent, SelectLibrary, SelectFtp, ColorPicker) {
function( Utils, Ui, SelectContent, SelectLibrary, SelectFtp, ColorPicker ) {
// create form view
return Backbone.Model.extend({
@@ -31,68 +31,30 @@ define(['utils/utils',
'ftpfile' : '_fieldFtp'
},
// initialize
initialize: function(app, options) {
initialize: function( app, options ) {
this.app = app;
},
/** Returns an input field for a given field type
*/
create: function(input_def) {
// add regular/default value if missing
if (input_def.value === undefined) {
input_def.value = null;
}
if (input_def.default_value === undefined) {
input_def.default_value = input_def.value;
}
// field wrapper
var field = null;
// get field class
var fieldClass = this.types[input_def.type];
if (fieldClass && typeof(this[fieldClass]) === 'function') {
field = this[fieldClass].call(this, input_def);
}
// identify field type
if (!field) {
// flag
create: function( input_def ) {
var fieldClass = this.types[ input_def.type ];
var field = typeof( this[ fieldClass ] ) === 'function' ? this[ fieldClass ].call( this, input_def ) : null;
if ( !field ) {
this.app.incompatible = true;
// with or without options
if (input_def.options) {
// assign select field
field = this._fieldSelect(input_def);
} else {
// assign text field
field = this._fieldText(input_def);
}
// log
field = input_def.options ? this._fieldSelect( input_def ) : this._fieldText( input_def );
Galaxy.emit.debug('form-parameters::_addRow()', 'Auto matched field type (' + input_def.type + ').');
}
// set field value
if (input_def.value !== undefined) {
field.value(input_def.value);
}
// return field element
input_def.value === undefined && ( input_def.value = null );
field.value( input_def.value );
return field;
},
/** Data input field
*/
_fieldData: function(input_def) {
if (this.app.options.is_workflow) {
input_def.info = 'Data input \'' + input_def.name + '\' (' + Utils.textify(input_def.extensions.toString()) + ')';
input_def.value = null;
return this._fieldHidden(input_def);
}
_fieldData: function( input_def ) {
var self = this;
return new SelectContent.View(this.app, {
return new SelectContent.View( this.app, {
id : 'field-' + input_def.id,
extensions : input_def.extensions,
optional : input_def.optional,
@@ -100,37 +62,33 @@ define(['utils/utils',
type : input_def.type,
data : input_def.options,
onchange : function() {
self.app.trigger('change');
self.app.trigger( 'change' );
}
});
},
/** Select/Checkbox/Radio options field
*/
_fieldSelect: function (input_def) {
// show text field in if dynamic fields are disabled e.g. in workflow editor
if (input_def.options.length == 0 && this.app.options.is_workflow) {
return this._fieldText(input_def);
_fieldSelect: function ( input_def ) {
// show text field e.g. in workflow editor
if( input_def.is_workflow ) {
return this._fieldText( input_def );
}
// customize properties
if (input_def.type == 'data_column') {
if ( input_def.type == 'data_column' ) {
input_def.error_text = 'Missing columns in referenced dataset.'
}
// configure options fields
var options = [];
for (var i in input_def.options) {
var option = input_def.options[i];
options.push({
label: option[0],
value: option[1]
});
}
_.each( input_def.options, function( option ) {
options.push( { label: option[ 0 ], value: option[ 1 ] } );
});
// identify display type
var SelectClass = Ui.Select;
switch (input_def.display) {
switch ( input_def.display ) {
case 'checkboxes':
SelectClass = Ui.Checkbox;
break;
@@ -139,28 +97,27 @@ define(['utils/utils',
break;
}
// select field
// create select field
var self = this;
return new SelectClass.View({
id : 'field-' + input_def.id,
data : options,
error_text : input_def.error_text || 'No options available',
optional : input_def.optional && input_def.default_value === null,
multiple : input_def.multiple,
optional : input_def.optional,
searchable : input_def.searchable,
onchange : function() {
self.app.trigger('change');
self.app.trigger( 'change' );
}
});
},
/** Drill down options field
*/
_fieldDrilldown: function (input_def) {
// show text field in if dynamic fields are disabled e.g. in workflow editor
if (input_def.options.length == 0 && this.app.options.is_workflow) {
return this._fieldText(input_def);
_fieldDrilldown: function ( input_def ) {
// show text field e.g. in workflow editor
if( input_def.is_workflow ) {
return this._fieldText( input_def );
}
// create drill down field
@@ -170,28 +127,25 @@ define(['utils/utils',
data : input_def.options,
display : input_def.display,
onchange : function() {
self.app.trigger('change');
self.app.trigger( 'change' );
}
});
},
/** Text input field
*/
_fieldText: function(input_def) {
_fieldText: function( input_def ) {
// field replaces e.g. a select field
if (input_def.options) {
// show text area if selecting multiple entries is allowed
if ( input_def.options ) {
input_def.area = input_def.multiple;
// validate value
if (!Utils.validate(input_def.value)) {
input_def.value = '';
if ( !Utils.validate( input_def.value ) ) {
input_def.value = null;
} else {
if ($.isArray(input_def.value)) {
if ( $.isArray( input_def.value ) ) {
var str_value = '';
for (var i in input_def.value) {
str_value += String(input_def.value[i]);
if (!input_def.multiple) {
for ( var i in input_def.value ) {
str_value += String( input_def.value[ i ] );
if ( !input_def.multiple ) {
break;
}
str_value += '\n';
@@ -200,36 +154,36 @@ define(['utils/utils',
}
}
}
// create input element
var self = this;
return new Ui.Input({
id : 'field-' + input_def.id,
area : input_def.area,
onchange : function() {
self.app.trigger('change');
onchange : function( new_value ) {
input_def.onchange ? input_def.onchange( new_value ) : self.app.trigger( 'change' );
}
});
},
/** Slider field
*/
_fieldSlider: function(input_def) {
_fieldSlider: function( input_def ) {
var self = this;
return new Ui.Slider.View({
id : 'field-' + input_def.id,
precise : input_def.type == 'float',
is_workflow : input_def.is_workflow,
min : input_def.min,
max : input_def.max,
onchange : function() {
self.app.trigger('change');
self.app.trigger( 'change' );
}
});
},
/** Hidden field
*/
_fieldHidden: function(input_def) {
_fieldHidden: function( input_def ) {
return new Ui.Hidden({
id : 'field-' + input_def.id,
info : input_def.info
@@ -238,54 +192,54 @@ define(['utils/utils',
/** Boolean field
*/
_fieldBoolean: function(input_def) {
_fieldBoolean: function( input_def ) {
var self = this;
return new Ui.RadioButton.View({
id : 'field-' + input_def.id,
data : [ { label : 'Yes', value : 'true' },
{ label : 'No', value : 'false' }],
onchange : function() {
self.app.trigger('change');
self.app.trigger( 'change' );
}
});
},
/** Color picker field
*/
_fieldColor: function(input_def) {
_fieldColor: function( input_def ) {
var self = this;
return new ColorPicker({
id : 'field-' + input_def.id,
onchange : function() {
self.app.trigger('change');
self.app.trigger( 'change' );
}
});
},
/** Library dataset field
*/
_fieldLibrary: function(input_def) {
_fieldLibrary: function( input_def ) {
var self = this;
return new SelectLibrary.View({
id : 'field-' + input_def.id,
optional : input_def.optional,
multiple : input_def.multiple,
onchange : function() {
self.app.trigger('change');
self.app.trigger( 'change' );
}
});
},
/** FTP file field
*/
_fieldFtp: function(input_def) {
_fieldFtp: function( input_def ) {
var self = this;
return new SelectFtp.View({
id : 'field-' + input_def.id,
optional : input_def.optional,
multiple : input_def.multiple,
onchange : function() {
self.app.trigger('change');
self.app.trigger( 'change' );
}
});
}
+22 -55
View File
@@ -5,30 +5,21 @@ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc']
/** This class creates a ui component which enables the dynamic creation of portlets
*/
var View = Backbone.View.extend({
// default options
optionsDefault : {
title : 'Section',
max : null,
min : null
},
/** Initialize
*/
initialize : function(options) {
// configure options
this.options = Utils.merge(options, this.optionsDefault);
// create new element
this.setElement('<div/>');
// link this
var self = this;
this.options = Utils.merge(options, {
title : 'Section',
empty_text : 'Not available.',
max : null,
min : null
});
this.setElement('<div/>');
// create button
this.button_new = new Ui.ButtonIcon({
icon : 'fa-plus',
title : 'Insert ' + options.title_new,
tooltip : 'Add new ' + options.title_new + ' block',
title : 'Insert ' + this.options.title_new,
tooltip : 'Add new ' + this.options.title_new + ' block',
floating: 'clear',
onclick : function() {
if (options.onnew) {
@@ -42,17 +33,11 @@ var View = Backbone.View.extend({
cls : 'ui-table-plain',
content : ''
});
// append button
this.$el.append(this.table.$el);
// add button
this.$el.append($('<div/>').append(this.button_new.$el));
// clear list
// reset list
this.list = {};
// number of available repeats
this.n = 0;
},
@@ -65,16 +50,11 @@ var View = Backbone.View.extend({
/** Add new repeat block
*/
add: function(options) {
// repeat block already exists
if (!options.id || this.list[options.id]) {
Galaxy.emit.debug('form-repeat::add()', 'Duplicate repeat block id.');
return;
}
// increase repeat block counter
this.n++;
// delete button
var button_delete = new Ui.ButtonIcon({
icon : 'fa-trash-o',
tooltip : 'Delete this repeat block',
@@ -85,8 +65,6 @@ var View = Backbone.View.extend({
}
}
});
// create portlet
var portlet = new Portlet.View({
id : options.id,
title : 'placeholder',
@@ -95,55 +73,44 @@ var View = Backbone.View.extend({
button_delete : button_delete
}
});
// append content
portlet.append(options.$el);
// tag as section row
portlet.$el.addClass('section-row');
// append to dom
this.list[options.id] = portlet;
// append to dom
this.table.add(portlet.$el);
this.table.append('row_' + options.id, true);
// validate maximum
if (this.options.max > 0 && this.n >= this.options.max) {
this.button_new.disable();
}
// refresh view
this._refresh();
},
/** Delete repeat block
*/
del: function(id) {
// could not find element
if (!this.list[id]) {
Galaxy.emit.debug('form-repeat::del()', 'Invalid repeat block id.');
return;
}
// decrease repeat block counter
this.n--;
// delete table row
var table_row = this.table.get('row_' + id);
table_row.remove();
// remove from list
delete this.list[id];
// enable new button
this.button_new.enable();
// refresh delete button visibility
this._refresh();
},
/** Hides add/del options
*/
hideOptions: function() {
this.button_new.$el.hide();
_.each( this.list, function( portlet ) {
portlet.hideOperation('button_delete');
});
if( _.isEmpty( this.list ) ) {
this.$el.append( $('<div/>').addClass( 'ui-form-info' ).html( this.options.empty_text ) );
}
},
/** Refresh view
*/
_refresh: function() {
+34 -133
View File
@@ -9,15 +9,9 @@ define(['utils/utils',
'mvc/form/form-input',
'mvc/form/form-parameters'],
function(Utils, Table, Ui, Portlet, Repeat, InputElement, Parameters) {
// create form view
var View = Backbone.View.extend({
// initialize
initialize: function(app, options) {
// link app
this.app = app;
// link inputs
this.inputs = options.inputs;
// fix table style
@@ -27,26 +21,17 @@ define(['utils/utils',
// this assist in transforming the form into a json structure
options.cls_tr = 'section-row';
// create table
// create/render views
this.table = new Table.View(options);
// create parameter handler
this.parameters = new Parameters(app, options);
// configure portlet and form table
this.setElement(this.table.$el);
// render section
this.render();
},
/** Render section view
*/
render: function() {
// reset table
this.table.delAll();
// load settings elements into table
for (var i in this.inputs) {
this.add(this.inputs[i]);
}
@@ -55,13 +40,8 @@ define(['utils/utils',
/** Add a new input element
*/
add: function(input) {
// link this
var self = this;
// clone definition
var input_def = jQuery.extend(true, {}, input);
// create unique id
input_def.id = input.id = Utils.uid();
// add to sequential list of inputs
@@ -70,19 +50,15 @@ define(['utils/utils',
// identify field type
var type = input_def.type;
switch(type) {
// conditional field
case 'conditional':
this._addConditional(input_def);
break;
// repeat block
case 'repeat':
this._addRepeat(input_def);
break;
// customized section
case 'section':
this._addSection(input_def);
break;
// default single element row
default:
this._addRow(input_def);
}
@@ -91,32 +67,18 @@ define(['utils/utils',
/** Add a conditional block
*/
_addConditional: function(input_def) {
// link this
var self = this;
// copy identifier
input_def.test_param.id = input_def.id;
// build test parameter
var field = this._addRow(input_def.test_param);
this.app.options.sustain_conditionals && ( input_def.test_param.disabled = true );
var field = this._addRow( input_def.test_param );
// set onchange event for test parameter
field.options.onchange = function(value) {
// identify the selected case
var selectedCase = self.app.data.matchCase(input_def, value);
// check value in order to hide/show options
for (var i in input_def.cases) {
// get case
var case_def = input_def.cases[i];
// identify subsection name
var section_id = input_def.id + '-section-' + i;
// identify row
var section_row = self.table.get(section_id);
// check if non-hidden elements exist
var nonhidden = false;
for (var j in case_def.inputs) {
if (!case_def.inputs[j].hidden) {
@@ -124,36 +86,23 @@ define(['utils/utils',
break;
}
}
// show/hide sub form
if (i == selectedCase && nonhidden) {
section_row.fadeIn('fast');
} else {
section_row.hide();
}
}
// refresh form inputs
self.app.trigger('change');
};
// add conditional sub sections
for (var i in input_def.cases) {
// create id tag
var sub_section_id = input_def.id + '-section-' + i;
// create sub section
var sub_section = new View(this.app, {
inputs : input_def.cases[i].inputs
});
// displays as grouped subsection
sub_section.$el.addClass('ui-table-section');
// create table row
this.table.add(sub_section.$el);
// append to table
this.table.append(sub_section_id);
}
@@ -164,46 +113,32 @@ define(['utils/utils',
/** Add a repeat block
*/
_addRepeat: function(input_def) {
// link this
var self = this;
// block index
var block_index = 0;
// create repeat block element
var repeat = new Repeat.View({
title : input_def.title,
title_new : input_def.title,
title : input_def.title || 'Repeat',
title_new : input_def.title || '',
min : input_def.min,
max : input_def.max,
onnew : function() {
// create
create(input_def.inputs);
// trigger refresh
self.app.trigger('change');
}
});
// helper function to create new repeat blocks
function create (inputs) {
// create id tag
var sub_section_id = input_def.id + '-section-' + (block_index++);
// create sub section
var sub_section = new View(self.app, {
inputs : inputs
});
// add tab
repeat.add({
id : sub_section_id,
$el : sub_section.$el,
ondel : function() {
// delete repeat block
repeat.del(sub_section_id);
// trigger refresh
self.app.trigger('change');
}
});
@@ -212,38 +147,27 @@ define(['utils/utils',
//
// add parsed/minimum number of repeat blocks
//
var n_min = input_def.min;
var n_cache = _.size(input_def.cache);
for (var i = 0; i < Math.max(n_cache, n_min); i++) {
var inputs = null;
if (i < n_cache) {
inputs = input_def.cache[i];
} else {
inputs = input_def.inputs;
}
// create repeat block
create(inputs);
var n_cache = _.size( input_def.cache );
for ( var i = 0; i < Math.max( Math.max( n_cache, input_def.min ), input_def.default ); i++ ) {
create( i < n_cache ? input_def.cache[ i ] : input_def.inputs );
}
// hide options
this.app.options.sustain_repeats && repeat.hideOptions();
// create input field wrapper
var input_element = new InputElement(this.app, {
label : input_def.title,
label : input_def.title || input_def.name,
help : input_def.help,
field : repeat
});
// create table row
this.table.add(input_element.$el);
// append row to table
this.table.append(input_def.id);
},
/** Add a customized section
*/
_addSection: function(input_def) {
// link this
var self = this;
// create sub section
@@ -260,88 +184,65 @@ define(['utils/utils',
// create portlet for sub section
var portlet = new Portlet.View({
title : input_def.title,
title : input_def.title || input_def.name,
cls : 'ui-portlet-section',
collapsible : true,
collapsed : true,
operations : {
button_visible: button_visible
}
});
portlet.append(sub_section.$el);
portlet.append($('<div/>').addClass('ui-table-form-info').html(input_def.help));
// add event handler visibility button
var visible = false;
portlet.$content.hide();
portlet.$header.css('cursor', 'pointer');
portlet.$header.on('click', function() {
if (visible) {
visible = false;
portlet.$content.hide();
button_visible.setIcon('fa-eye-slash');
portlet.append( sub_section.$el );
portlet.append( $( '<div/>' ).addClass( 'ui-form-info' ).html( input_def.help ) );
portlet.setOperation( 'button_visible', function() {
if( portlet.collapsed ) {
portlet.expand();
} else {
visible = true;
portlet.$content.fadeIn('fast');
button_visible.setIcon('fa-eye');
portlet.collapse();
}
});
// add expansion event handler
this.app.on('expand', function(input_id) {
(portlet.$el.find('#' + input_id).length > 0) && !visible && portlet.$header.trigger('click');
portlet.on( 'expanded', function() {
button_visible.setIcon( 'fa-eye' );
});
portlet.on( 'collapsed', function() {
button_visible.setIcon( 'fa-eye-slash' );
});
this.app.on( 'expand', function( input_id ) {
( portlet.$( '#' + input_id ).length > 0 ) && portlet.expand();
});
// show sub section if requested
if (input_def.expanded) {
portlet.$header.trigger('click');
}
input_def.expanded && portlet.expand();
// create table row
this.table.add(portlet.$el);
// append row to table
this.table.append(input_def.id);
},
/** Add a single input field element
*/
_addRow: function(input_def) {
// get id
var id = input_def.id;
// create input field
var field = this.parameters.create(input_def);
// add to field list
this.app.field_list[id] = field;
// create input field wrapper
var input_element = new InputElement(this.app, {
name : input_def.name,
label : input_def.label || input_def.name,
value : input_def.value,
default_value : input_def.default_value,
collapsible : input_def.collapsible,
text_value : input_def.text_value || input_def.value,
collapsible_value : input_def.collapsible_value,
collapsible_preview : input_def.collapsible_preview,
help : input_def.help,
argument : input_def.argument,
disabled : input_def.disabled,
field : field
});
// add to element list
this.app.element_list[id] = input_element;
// create table row
this.table.add(input_element.$el);
// append to table
this.table.append(id);
// hide row if neccessary
if (input_def.hidden) {
this.table.get(id).hide();
}
// return created field
input_def.hidden && this.table.get(id).hide();
return field;
}
});
@@ -1,7 +1,5 @@
// dependencies
define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-tabs', 'mvc/tools/tools-template'],
function(Utils, Ui, Tabs, ToolTemplate) {
define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-tabs'], function(Utils, Ui, Tabs) {
// hda/hdca content selector ui element
var View = Backbone.View.extend({
// initialize
@@ -101,8 +99,11 @@ var View = Backbone.View.extend({
value : 'collection',
tooltip : 'Dataset collection'
});
var multiple = this.mode == 'multiple';
this.select_collection = new Ui.Select.View({
error_text : hdca_error,
multiple : multiple,
searchable : false,
optional : options.optional,
onchange : function() {
self.trigger('change');
@@ -194,6 +195,7 @@ var View = Backbone.View.extend({
for (var i in options) {
var item = options[i];
select_options.push({
hid : item.hid,
label: item.hid + ': ' + item.name,
value: item.id
});
@@ -201,7 +203,7 @@ var View = Backbone.View.extend({
self.history[item.id + '_' + item.src] = item;
}
// update field
field.update(select_options);
field.add( select_options, function( a, b ) { return b.hid - a.hid } );
}
}
@@ -222,11 +224,11 @@ var View = Backbone.View.extend({
for (var i in new_value.values) {
list.push(new_value.values[i].id);
}
// identify suitable select field
if (new_value && new_value.values.length > 0 && new_value.values[0].src == 'hdca') {
this.current = 'collection';
this.select_collection.value(list[0]);
this.select_collection.value(list);
} else {
if (this.mode == 'multiple') {
this.current = 'multiple';
@@ -331,7 +333,7 @@ var View = Backbone.View.extend({
/** Batch message template */
template_batch: function() {
return '<div class="ui-table-form-info">' +
return '<div class="ui-form-info">' +
'<i class="fa fa-sitemap" style="font-size: 1.2em; padding: 2px 5px;"/>' +
'This is a batch mode input field. A separate job will be triggered for each dataset.' +
'</div>';
+16 -38
View File
@@ -1,43 +1,18 @@
/**
This is the main class of the form plugin. It is referenced as 'app' in all lower level modules.
*/
define(['utils/utils', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
'mvc/form/form-section', 'mvc/form/form-data'],
define(['utils/utils', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc', 'mvc/form/form-section', 'mvc/form/form-data'],
function(Utils, Portlet, Ui, FormSection, FormData) {
// create form view
return Backbone.View.extend({
// initialize
initialize: function(options) {
// options
this.optionsDefault = {
// uses workflow editor mode i.e. text instead of select fields
is_workflow : false,
// shows errors on start
this.options = Utils.merge(options, {
initial_errors : false,
// portlet style
cls : 'ui-portlet-limited'
};
// configure options
this.options = Utils.merge(options, this.optionsDefault);
// log options
Galaxy.emit.debug('form-view::initialize()', 'Ready to build form.', this.options);
// link galaxy modal or create one
var galaxy = parent.Galaxy;
if (galaxy && galaxy.modal) {
this.modal = galaxy.modal;
} else {
this.modal = new Ui.Modal.View();
}
// set element
cls : 'ui-portlet-limited',
icon : ''
});
this.modal = ( parent.Galaxy && parent.Galaxy.modal ) || new Ui.Modal.View();
this.setElement('<div/>');
// build this form
this._build();
this.render();
},
/** Update available options */
@@ -137,9 +112,9 @@ define(['utils/utils', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
}
},
/** Main tool form build function. This function is called once a new model is available.
/** Render tool form
*/
_build: function() {
render: function() {
// link this
var self = this;
@@ -157,7 +132,7 @@ define(['utils/utils', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
this.element_list = {};
// creates a json data structure from the input form
this.data = new FormData(this);
this.data = new FormData.Manager(this);
// create ui elements
this._renderForm();
@@ -186,6 +161,7 @@ define(['utils/utils', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
this.element_list[i].reset();
}
});
return this;
},
/** Renders the UI elements required for the form
@@ -204,15 +180,17 @@ define(['utils/utils', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
// create portlet
this.portlet = new Portlet.View({
icon : 'fa-wrench',
icon : this.options.icon,
title : this.options.title,
cls : this.options.cls,
operations : this.options.operations,
buttons : this.options.buttons
buttons : this.options.buttons,
collapsible : this.options.collapsible,
collapsed : this.options.collapsed
});
// append message
this.portlet.append(this.message.$el.addClass('ui-margin-top'));
this.portlet.append(this.message.$el);
// append tool section
this.portlet.append(this.section.$el);
@@ -83,6 +83,7 @@ return Backbone.View.extend({
this.init_grid_controls();
// attach global event handler
// TODO: redundant (the onload/standard page handlers do this) - but needed because these are constructed after page ready
init_refresh_on_change();
},
+185 -84
View File
@@ -1,99 +1,200 @@
define([
"mvc/ui/ui-modal",
"utils/localization"
], function( _l ){
/* =============================================================================
Wrapper function around the global Galaxy.modal for use when copying histories.
], function( MODAL, _l ){
==============================================================================*/
function _renderBody( vars ){
return [
'<form action="">',
'use strict';
//==============================================================================
/**
* A dialog/modal that allows copying a user history or 'importing' from user
* another. Generally called via historyCopyDialog below.
* @type {Object}
*/
var CopyDialog = {
// language related strings/fns
defaultName : _.template( "Copy of '<%- name %>'" ),
title : _.template( _l( 'Copying history' ) + ' "<%- name %>"' ),
submitLabel : _l( 'Copy' ),
errorMessage : _l( 'History could not be copied' ),
progressive : _l( 'Copying history' ),
activeLabel : _l( 'Copy only the active, non-deleted datasets' ),
allLabel : _l( 'Copy all datasets including deleted ones' ),
anonWarning : _l( 'As an anonymous user, unless you login or register, you will lose your current history ' ) +
_l( 'after copying this history. ' ),
// template for modal body
_template : _.template([
//TODO: remove inline styles
// show a warning message for losing current to anon users
'<% if( isAnon ){ %>',
'<div class="warningmessage">',
'<%- anonWarning %>',
_l( 'You can' ),
' <a href="/user/login">', _l( 'login here' ), '</a> ', _l( 'or' ), ' ',
' <a href="/user/create">', _l( 'register here' ), '</a>.',
'</div>',
'<% } %>',
'<form>',
'<label for="copy-modal-title">',
_l( 'Enter a title for the copied history' ), ':',
_l( 'Enter a title for the new history' ), ':',
'</label><br />',
'<input id="copy-modal-title" class="form-control" style="width: 100%" value="', vars.defaultCopyName, '" />',
'<br />',
'<p>', _l( 'You can make a copy of the history that includes all datasets in the original history' ),
_l( ' or just the active (not deleted) datasets.' ), '</p>',
// copy non-deleted is the default
'<input name="copy-what" type="radio" id="copy-non-deleted" value="copy-non-deleted" checked />',
'<label for="copy-non-deleted">', _l( 'Copy only active (not deleted) datasets' ), '</label><br />',
'<input name="copy-what" type="radio" id="copy-all" value="copy-all" />',
'<label for="copy-all">', _l( 'Copy all datasets, including deleted ones' ), '</label><br />',
// TODO: could use required here and the form validators
// NOTE: use unescaped here if escaped in the modal function below
'<input id="copy-modal-title" class="form-control" style="width: 100%" value="<%= name %>" />',
'<p class="invalid-title bg-danger" style="color: red; margin: 8px 0px 8px 0px; display: none">',
_l( 'Please enter a valid history title' ),
'</p>',
// if allowAll, add the option to copy deleted datasets, too
'<% if( allowAll ){ %>',
'<br />',
'<p>', _l( 'Choose which datasets from the original history to include:' ), '</p>',
// copy non-deleted is the default
'<input name="copy-what" type="radio" id="copy-non-deleted" value="copy-non-deleted" ',
'<% if( copyWhat === "copy-non-deleted" ){ print( "checked" ); } %>/>',
'<label for="copy-non-deleted"> <%- activeLabel %></label>',
'<br />',
'<input name="copy-what" type="radio" id="copy-all" value="copy-all" ',
'<% if( copyWhat === "copy-all" ){ print( "checked" ); } %>/>',
'<label for="copy-all"> <%- allLabel %></label>',
'<% } %>',
'</form>'
].join('');
}
].join( '' )),
function _validateName( name ){
if( !name ){
if( !Galaxy.modal.$( '#invalid-title' ).size() ){
var $invalidTitle = $( '<p/>' ).attr( 'id', 'invalid-title' )
.css({ color: 'red', 'margin-top': '8px' })
.addClass( 'bg-danger' ).text( _l( 'Please enter a valid history title' ) );
Galaxy.modal.$( '.modal-body' ).append( $invalidTitle );
// empty modal body and let the user know the copy is happening
_showAjaxIndicator : function _showAjaxIndicator(){
var indicator = '<p><span class="fa fa-spinner fa-spin"></span> ' + this.progressive + '...</p>';
this.modal.$( '.modal-body' ).empty().append( indicator ).css({ 'margin-top': '8px' });
},
// (sorta) public interface - display the modal, render the form, and potentially copy the history
// returns a jQuery.Deferred done->history copied, fail->user cancelled
dialog : function _dialog( modal, history, options ){
options = options || {};
var dialog = this,
deferred = jQuery.Deferred(),
// TODO: getting a little byzantine here
defaultCopyNameFn = options.nameFn || this.defaultName,
defaultCopyName = defaultCopyNameFn({ name: history.get( 'name' ) }),
// TODO: these two might be simpler as one 3 state option (all,active,no-choice)
defaultCopyWhat = options.allDatasets? 'copy-all' : 'copy-non-deleted',
allowAll = !_.isUndefined( options.allowAll )? options.allowAll : true,
autoClose = !_.isUndefined( options.autoClose )? options.autoClose : true;
this.modal = modal;
// validate the name and copy if good
function checkNameAndCopy(){
var name = modal.$( '#copy-modal-title' ).val();
if( !name ){
modal.$( '.invalid-title' ).show();
return;
}
// get further settings, shut down and indicate the ajax call, then hide and resolve/reject
var copyAllDatasets = modal.$( 'input[name="copy-what"]:checked' ).val() === 'copy-all';
modal.$( 'button' ).prop( 'disabled', true );
dialog._showAjaxIndicator();
history.copy( true, name, copyAllDatasets )
.done( function( response ){
deferred.resolve( response );
})
//TODO: make this unneccessary with pub-sub error or handling via Galaxy
.fail( function(){
alert([ dialog.errorMessage, _l( 'Please contact a Galaxy administrator' ) ].join( '. ' ));
deferred.rejectWith( deferred, arguments );
})
.always( function(){
if( autoClose ){ modal.hide(); }
});
}
return false;
}
return name;
}
function _renderCopyIndicator(){
return $([
'<p>', '<span class="fa fa-spinner fa-spin"></span> ', _l( 'Copying history' ), '...', '</p>'
].join( '' ))
//TODO: move out of inline
.css({ 'margin-top': '8px' });
}
var originalClosingCallback = options.closing_callback;
modal.show( _.extend( options, {
title : this.title({ name: history.get( 'name' ) }),
body : $( dialog._template({
name : defaultCopyName,
isAnon : Galaxy.user.isAnonymous(),
allowAll : allowAll,
copyWhat : defaultCopyWhat,
activeLabel : this.activeLabel,
allLabel : this.allLabel,
anonWarning : this.anonWarning,
})),
buttons : _.object([
[ _l( 'Cancel' ), function(){ modal.hide(); } ],
[ this.submitLabel, checkNameAndCopy ]
]),
height : 'auto',
closing_events : true,
closing_callback: function _historyCopyClose( cancelled ){
if( cancelled ){
deferred.reject({ cancelled : true });
}
if( originalClosingCallback ){
originalClosingCallback( cancelled );
}
}
}));
/** show the dialog and handle validation, ajax, and callbacks */
function historyCopyDialog( history, options ){
// set the default dataset copy, autofocus the title, and set up for a simple return
modal.$( '#copy-modal-title' ).focus().select();
modal.$( '#copy-modal-title' ).on( 'keydown', function( ev ){
if( ev.keyCode === 13 ){
ev.preventDefault();
checkNameAndCopy();
}
});
return deferred;
},
};
//==============================================================================
// maintain the (slight) distinction between copy and import
/**
* Subclass CopyDialog to use the import language.
*/
var ImportDialog = _.extend( {}, CopyDialog, {
defaultName : _.template( "imported: <%- name %>" ),
title : _.template( _l( 'Importing history' ) + ' "<%- name %>"' ),
submitLabel : _l( 'Import' ),
errorMessage : _l( 'History could not be imported' ),
progressive : _l( 'Importing history' ),
activeLabel : _l( 'Import only the active, non-deleted datasets' ),
allLabel : _l( 'Import all datasets including deleted ones' ),
anonWarning : _l( 'As an anonymous user, unless you login or register, you will lose your current history ' ) +
_l( 'after importing this history. ' ),
});
//==============================================================================
/**
* Main interface for both history import and history copy dialogs.
* @param {Backbone.Model} history the history to copy
* @param {Object} options a hash
* @return {jQuery.Deferred} promise that fails on close and succeeds on copy
*
* options:
* (this object is also passed to the modal used to display the dialog and accepts modal options)
* {Function} nameFn if defined, use this to build the default name shown to the user
* (the fn is passed: {name: <original history's name>})
* {bool} useImport if true, use the 'import' language (instead of Copy)
* {bool} allowAll if true, allow the user to choose between copying all datasets and
* only non-deleted datasets
* {String} allDatasets default initial checked radio button: 'copy-all' or 'copy-non-deleted',
*/
var historyCopyDialog = function( history, options ){
options = options || {};
// fall back to un-notifying copy
if( !( Galaxy && Galaxy.modal ) ){
return history.copy();
}
// create our own modal if Galaxy doesn't have one (mako tab without use_panels)
var modal = window.parent.Galaxy.modal || new MODAL.View({});
return options.useImport?
ImportDialog.dialog( modal, history, options ):
CopyDialog.dialog( modal, history, options );
};
// maybe better as multiselect dialog?
var historyName = _.escape(history.get( 'name' )),
defaultCopyName = "Copy of '" + historyName + "'";
function copyHistory( name ){
var copyAllDatasets = Galaxy.modal.$( 'input[name="copy-what"]:checked' ).val() === 'copy-all',
$copyIndicator = _renderCopyIndicator();
Galaxy.modal.$( '.modal-body' ).children().replaceWith( $copyIndicator );
Galaxy.modal.$( 'button' ).prop( 'disabled', true );
history.copy( true, name, copyAllDatasets )
//TODO: make this unneccessary with pub-sub error or handling via Galaxy
.fail( function(){
alert( _l( 'History could not be copied. Please contact a Galaxy administrator' ) );
})
.always( function(){
Galaxy.modal.hide();
});
}
function checkNameAndCopy(){
var name = Galaxy.modal.$( '#copy-modal-title' ).val();
if( !_validateName( name ) ){ return; }
copyHistory( name );
}
Galaxy.modal.show( _.extend({
title : _l( 'Copying history' ) + ' "' + historyName + '"',
body : $( _renderBody({ defaultCopyName: defaultCopyName }) ),
buttons : {
'Cancel' : function(){ Galaxy.modal.hide(); },
'Copy' : checkNameAndCopy
},
closing_events : true
}, options ));
$( '#copy-modal-title' ).focus().select();
$( '#copy-modal-title' ).on( 'keydown', function( ev ){
if( ev.keyCode === 13 ){
checkNameAndCopy();
}
});
// TODO: return a promise completed on copy, close, or error
}
//==============================================================================
return historyCopyDialog;
@@ -4,6 +4,9 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( DATASET_LI_EDIT, HDA_LI, BASE_MVC, _l ){
'use strict';
//==============================================================================
var _super = DATASET_LI_EDIT.DatasetListItemEdit;
/** @class Editing view for HistoryDatasetAssociation.
+3 -1
View File
@@ -3,7 +3,9 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( DATASET_LI, BASE_MVC, _l ){
/* global Backbone */
'use strict';
//==============================================================================
var _super = DATASET_LI.DatasetListItemView;
/** @class Read only view for HistoryDatasetAssociation.
@@ -4,6 +4,9 @@ define([
"mvc/base-mvc",
"utils/localization"
], function( DATASET, HISTORY_CONTENT, BASE_MVC, _l ){
'use strict';
//==============================================================================
var _super = DATASET.DatasetAssociation,
hcontentMixin = HISTORY_CONTENT.HistoryContentMixin;
@@ -22,7 +25,7 @@ var HistoryDatasetAssociation = _super.extend( BASE_MVC.mixin( hcontentMixin,
constructor : function( attrs, options ){
hcontentMixin.constructor.call( this, attrs, options );
},
/** default attributes for a model */
defaults : _.extend( {}, _super.prototype.defaults, hcontentMixin.defaults, {
model_class : 'HistoryDatasetAssociation'
@@ -1,9 +1,12 @@
define([
"mvc/history/hdca-li",
"mvc/collection/collection-panel-edit",
"mvc/collection/collection-view-edit",
"ui/fa-icon-button",
"utils/localization"
], function( HDCA_LI, DC_PANEL_EDIT, faIconButton, _l ){
], function( HDCA_LI, DC_VIEW_EDIT, faIconButton, _l ){
'use strict';
//==============================================================================
var _super = HDCA_LI.HDCAListItemView;
/** @class Editing view for HistoryDatasetCollectionAssociation.
@@ -18,11 +21,11 @@ var HDCAListItemEdit = _super.extend(
_getFoldoutPanelClass : function(){
switch( this.model.get( 'collection_type' ) ){
case 'list':
return DC_PANEL_EDIT.ListCollectionPanelEdit;
return DC_VIEW_EDIT.ListCollectionViewEdit;
case 'paired':
return DC_PANEL_EDIT.PairCollectionPanelEdit;
return DC_VIEW_EDIT.PairCollectionViewEdit;
case 'list:paired':
return DC_PANEL_EDIT.ListOfPairsCollectionPanelEdit;
return DC_VIEW_EDIT.ListOfPairsCollectionViewEdit;
}
throw new TypeError( 'Uknown collection_type: ' + this.model.get( 'collection_type' ) );
},
+10 -8
View File
@@ -1,11 +1,13 @@
define([
"mvc/dataset/states",
"mvc/collection/collection-li",
"mvc/collection/collection-panel",
"mvc/collection/collection-view",
"mvc/base-mvc",
"utils/localization"
], function( STATES, DC_LI, DC_PANEL, BASE_MVC, _l ){
/* global Backbone */
], function( STATES, DC_LI, DC_VIEW, BASE_MVC, _l ){
'use strict';
//==============================================================================
var _super = DC_LI.DCListItemView;
/** @class Read only view for HistoryDatasetCollectionAssociation (a dataset collection inside a history).
@@ -22,20 +24,20 @@ var HDCAListItemView = _super.extend(
_setUpListeners : function(){
_super.prototype._setUpListeners.call( this );
this.model.on({
this.listenTo( this.model, {
'change:populated change:visible' : function( model, options ){ this.render(); },
}, this );
});
},
/** Override to provide the proper collections panels as the foldout */
_getFoldoutPanelClass : function(){
switch( this.model.get( 'collection_type' ) ){
case 'list':
return DC_PANEL.ListCollectionPanel;
return DC_VIEW.ListCollectionView;
case 'paired':
return DC_PANEL.PairCollectionPanel;
return DC_VIEW.PairCollectionView;
case 'list:paired':
return DC_PANEL.ListOfPairsCollectionPanel;
return DC_VIEW.ListOfPairsCollectionView;
}
throw new TypeError( 'Uknown collection_type: ' + this.model.get( 'collection_type' ) );
},
@@ -3,6 +3,9 @@ define([
"mvc/history/history-content-model",
"utils/localization"
], function( DC_MODEL, HISTORY_CONTENT, _l ){
'use strict';
/*==============================================================================
Models for DatasetCollections contained within a history.
@@ -4,6 +4,8 @@ define([
"utils/localization"
], function( STATES, BASE_MVC, _l ){
'use strict';
var logNamespace = 'history';
//==============================================================================
/** How the type_id attribute is built for the history's mixed contents collection */
@@ -94,7 +96,7 @@ var HistoryContentMixin = {
//TODO: global
//TODO: these are probably better done on the leaf classes
/** history content goes through the 'api/histories' API */
urlRoot: ( window.Galaxy? Galaxy.options.root : '/' ) + 'api/histories/',
urlRoot: Galaxy.root + 'api/histories/',
/** full url spec. for this content */
url : function(){
@@ -6,6 +6,8 @@ define([
"utils/localization"
], function( HISTORY_CONTENT, HDA_MODEL, HDCA_MODEL, BASE_MVC, _l ){
'use strict';
var logNamespace = 'history';
//==============================================================================
/** @class Backbone collection for history content.
@@ -71,7 +73,7 @@ var HistoryContents = Backbone.Collection
},
/** root api url */
urlRoot : galaxy_config.root + 'api/histories',
urlRoot : Galaxy.root + 'api/histories',
/** complete api url */
url : function(){
return this.urlRoot + '/' + this.historyId + '/contents';
@@ -6,6 +6,8 @@ define([
"utils/localization"
], function( HISTORY_CONTENTS, UTILS, BASE_MVC, _l ){
'use strict';
var logNamespace = 'history';
//==============================================================================
/** @class Model for a Galaxy history resource - both a record of user
@@ -25,12 +27,11 @@ var History = Backbone.Model
name : 'Unnamed History',
state : 'new',
diskSize : 0,
deleted : false
},
// ........................................................................ urls
urlRoot: galaxy_config.root + 'api/histories',
urlRoot: Galaxy.root + 'api/histories',
// ........................................................................ set up/tear down
/** Set up the model
@@ -79,7 +80,7 @@ var History = Backbone.Model
if( this.contents ){
this.contents.historyId = newId;
}
}, this );
});
},
//TODO: see base-mvc
@@ -116,16 +117,16 @@ var History = Backbone.Model
},
// ........................................................................ common queries
/** T/F is this history owned by the current user (Galaxy.currUser)
/** T/F is this history owned by the current user (Galaxy.user)
* Note: that this will return false for an anon user even if the history is theirs.
*/
ownedByCurrUser : function(){
// no currUser
if( !Galaxy || !Galaxy.currUser ){
if( !Galaxy || !Galaxy.user ){
return false;
}
// user is anon or history isn't owned
if( Galaxy.currUser.isAnonymous() || Galaxy.currUser.id !== this.get( 'user_id' ) ){
if( Galaxy.user.isAnonymous() || Galaxy.user.id !== this.get( 'user_id' ) ){
return false;
}
return true;
@@ -277,7 +278,7 @@ var History = Backbone.Model
setAsCurrent : function(){
var history = this,
xhr = jQuery.getJSON( galaxy_config.root + 'history/set_as_current?id=' + this.id );
xhr = jQuery.getJSON( Galaxy.root + 'history/set_as_current?id=' + this.id );
xhr.done( function(){
history.trigger( 'set-as-current', history );
@@ -310,9 +311,9 @@ History.getHistoryData = function getHistoryData( historyId, options ){
function getHistory( id ){
// get the history data
if( historyId === 'current' ){
return jQuery.getJSON( galaxy_config.root + 'history/current_history_json' );
return jQuery.getJSON( Galaxy.root + 'history/current_history_json' );
}
return jQuery.ajax( galaxy_config.root + 'api/histories/' + historyId );
return jQuery.ajax( Galaxy.root + 'api/histories/' + historyId );
}
function isEmpty( historyData ){
// get the number of hdas accrd. to the history
@@ -338,7 +339,7 @@ History.getHistoryData = function getHistoryData( historyId, options ){
// by frontend.
data.dataset_collection_details = hdcaDetailIds.join( ',' );
}
return jQuery.ajax( galaxy_config.root + 'api/histories/' + historyData.id + '/contents', { data: data });
return jQuery.ajax( Galaxy.root + 'api/histories/' + historyData.id + '/contents', { data: data });
}
// getting these concurrently is 400% slower (sqlite, local, vanilla) - so:
@@ -501,7 +502,7 @@ var HistoryCollection = Backbone.Collection
this.setUpListeners();
},
urlRoot : ( window.galaxy_config? galaxy_config.root : '/' ) + 'api/histories',
urlRoot : Galaxy.root + 'api/histories',
url : function(){ return this.urlRoot; },
/** returns map of default filters and settings for fetching from the API */
@@ -541,7 +542,7 @@ var HistoryCollection = Backbone.Collection
this.trigger( 'no-longer-current', oldCurrentId );
this.currentHistoryId = history.id;
}
}, this );
});
},
/** override to allow passing options.order and setting the sort order to one of sortOrders */
@@ -609,7 +610,7 @@ var HistoryCollection = Backbone.Collection
create : function create( data, hdas, historyOptions, xhrOptions ){
//TODO: .create is actually a collection function that's overridden here
var collection = this,
xhr = jQuery.getJSON( galaxy_config.root + 'history/create_new_current' );
xhr = jQuery.getJSON( Galaxy.root + 'history/create_new_current' );
return xhr.done( function( newData ){
collection.setCurrent( new History( newData, [], historyOptions || {} ) );
});
@@ -9,6 +9,8 @@ define([
'libs/d3'
], function( JobDAG, JOB, JOB_LI, HISTORY_CONTENT, DATASET_LI, BASE_MVC, _l ){
'use strict';
var logNamespace = 'history';
// ============================================================================
/*
@@ -157,8 +159,8 @@ var HistoryStructureComponent = Backbone.View.extend( BASE_MVC.LoggableMixin ).e
// create the bbone view for the job (to be positioned later accrd. to the layout) and cache
var li = new view.JobItemClass({ model: job, tool: jobData.tool, jobData: jobData });
li.on( 'expanding expanded collapsing collapsed', view.renderGraph, view );
li.foldout.on( 'view:expanding view:expanded view:collapsing view:collapsed', view.renderGraph, view );
view.listenTo( li, 'expanding expanded collapsing collapsed', view.renderGraph );
view.listenTo( li.foldout, 'view:expanding view:expanded view:collapsing view:collapsed', view.renderGraph );
return li;
},
@@ -169,7 +171,7 @@ var HistoryStructureComponent = Backbone.View.extend( BASE_MVC.LoggableMixin ).e
typeId = HISTORY_CONTENT.typeIdStr( content.history_content_type, content.id );
content = view.model.contents.get( typeId );
var li = new view.ContentItemClass({ model: content });
li.on( 'expanding expanded collapsing collapsed', view.renderGraph, view );
view.listenTo( li, 'expanding expanded collapsing collapsed', view.renderGraph );
return li;
},
@@ -1,25 +1,28 @@
define([
"mvc/history/history-panel",
"mvc/history/history-view",
"mvc/history/hda-li",
"mvc/history/hdca-li",
"mvc/base-mvc",
"utils/localization"
], function( HPANEL, HDA_LI, HDCA_LI, BASE_MVC, _l ){
], function( HISTORY_VIEW, HDA_LI, HDCA_LI, BASE_MVC, _l ){
'use strict';
/* =============================================================================
TODO:
============================================================================= */
var _super = HPANEL.HistoryPanel;
var _super = HISTORY_VIEW.HistoryView;
// used in history/display.mako and history/embed.mako
/** @class View/Controller for a tabular view of the history model.
*
* As ReadOnlyHistoryPanel, but with:
* As ReadOnlyHistoryView, but with:
* history annotation always shown
* datasets displayed in a table:
* datasets in left cells, dataset annotations in the right
*/
var AnnotatedHistoryPanel = _super.extend(
/** @lends AnnotatedHistoryPanel.prototype */{
var AnnotatedHistoryView = _super.extend(
/** @lends AnnotatedHistoryView.prototype */{
/** logger used to record this.log messages, commonly set to console */
//logger : console,
@@ -108,13 +111,13 @@ var AnnotatedHistoryPanel = _super.extend(
// ........................................................................ misc
/** Return a string rep of the history */
toString : function(){
return 'AnnotatedHistoryPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'AnnotatedHistoryView(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
//==============================================================================
return {
AnnotatedHistoryPanel : AnnotatedHistoryPanel
AnnotatedHistoryView : AnnotatedHistoryView
};
});
@@ -1,15 +1,17 @@
define([
"mvc/history/history-model",
"mvc/history/history-panel-edit",
"mvc/collection/collection-panel",
"mvc/history/history-view-edit",
"mvc/base-mvc",
"utils/localization"
], function( HISTORY_MODEL, HPANEL_EDIT, DC_PANEL, BASE_MVC, _l ){
], function( HISTORY_MODEL, HISTORY_VIEW_EDIT, BASE_MVC, _l ){
'use strict';
// ============================================================================
/** session storage for history panel preferences (and to maintain state)
*/
var HistoryPanelPrefs = BASE_MVC.SessionStorageModel.extend(
/** @lends HistoryPanelPrefs.prototype */{
var HistoryViewPrefs = BASE_MVC.SessionStorageModel.extend(
/** @lends HistoryViewPrefs.prototype */{
defaults : {
/** should the tags editor be shown or hidden initially? */
tagsEditorShown : false,
@@ -23,12 +25,12 @@ var HistoryPanelPrefs = BASE_MVC.SessionStorageModel.extend(
scrollPosition : 0
},
toString : function(){
return 'HistoryPanelPrefs(' + JSON.stringify( this.toJSON() ) + ')';
return 'HistoryViewPrefs(' + JSON.stringify( this.toJSON() ) + ')';
}
});
/** key string to store panel prefs (made accessible on class so you can access sessionStorage directly) */
HistoryPanelPrefs.storageKey = function storageKey(){
HistoryViewPrefs.storageKey = function storageKey(){
return ( 'history-panel' );
};
@@ -36,7 +38,7 @@ HistoryPanelPrefs.storageKey = function storageKey(){
TODO:
============================================================================= */
var _super = HPANEL_EDIT.HistoryPanelEdit;
var _super = HISTORY_VIEW_EDIT.HistoryViewEdit;
// used in root/index.mako
/** @class View/Controller for the user's current history model as used in the history
* panel (current right hand panel) of the analysis page.
@@ -45,8 +47,8 @@ var _super = HPANEL_EDIT.HistoryPanelEdit;
* will poll for updates.
* displays datasets in reverse hid order.
*/
var CurrentHistoryPanel = _super.extend(
/** @lends CurrentHistoryPanel.prototype */{
var CurrentHistoryView = _super.extend(
/** @lends CurrentHistoryView.prototype */{
/** logger used to record this.log messages, commonly set to console */
//logger : console,
@@ -68,9 +70,9 @@ var CurrentHistoryPanel = _super.extend(
// ---- persistent preferences
/** maintain state / preferences over page loads */
this.preferences = new HistoryPanelPrefs( _.extend({
id : HistoryPanelPrefs.storageKey()
}, _.pick( attributes, _.keys( HistoryPanelPrefs.prototype.defaults ) )));
this.preferences = new HistoryViewPrefs( _.extend({
id : HistoryViewPrefs.storageKey()
}, _.pick( attributes, _.keys( HistoryViewPrefs.prototype.defaults ) )));
_super.prototype.initialize.call( this, attributes );
@@ -111,7 +113,7 @@ var CurrentHistoryPanel = _super.extend(
var panel = this,
historyFn = function(){
// make this current and get history data with one call
return jQuery.getJSON( galaxy_config.root + 'history/set_as_current?id=' + historyId );
return jQuery.getJSON( Galaxy.root + 'history/set_as_current?id=' + historyId );
// method : 'PUT'
//});
};
@@ -123,14 +125,14 @@ var CurrentHistoryPanel = _super.extend(
/** creates a new history on the server and sets it as the user's current history */
createNewHistory : function( attributes ){
if( !Galaxy || !Galaxy.currUser || Galaxy.currUser.isAnonymous() ){
if( !Galaxy || !Galaxy.user || Galaxy.user.isAnonymous() ){
this.displayMessage( 'error', _l( 'You must be logged in to create histories' ) );
return $.when();
}
var panel = this,
historyFn = function(){
// create a new history and save: the server will return the proper JSON
return jQuery.getJSON( galaxy_config.root + 'history/create_new_current' );
return jQuery.getJSON( Galaxy.root + 'history/create_new_current' );
};
// id undefined bc there is no historyId yet - the server will provide
@@ -156,30 +158,25 @@ var CurrentHistoryPanel = _super.extend(
_setUpCollectionListeners : function(){
_super.prototype._setUpCollectionListeners.call( this );
//TODO:?? may not be needed? see history-panel-edit, 369
//TODO:?? may not be needed? see history-view-edit, 369
// if a hidden item is created (gen. by a workflow), moves thru the updater to the ready state,
// then: remove it from the collection if the panel is set to NOT show hidden datasets
this.collection.on( 'state:ready', function( model, newState, oldState ){
this.listenTo( this.collection, 'state:ready', function( model, newState, oldState ){
if( ( !model.get( 'visible' ) )
&& ( !this.storage.get( 'show_hidden' ) ) ){
this.removeItemView( model );
}
}, this );
});
},
/** listening for history events */
_setUpModelListeners : function(){
_super.prototype._setUpModelListeners.call( this );
// ---- history
// update the quota meter when current history changes size
//TODO: global - have Galaxy listen to this instead
if( Galaxy && Galaxy.quotaMeter ){
this.listenTo( this.model, 'change:nice_size', function(){
//this.info( '!! model size changed:', this.model.get( 'nice_size' ) )
Galaxy.quotaMeter.update();
});
}
// re-broadcast any model change events so that listeners don't have to re-bind to each history
this.listenTo( this.model, 'change:nice_size change:size', function(){
this.trigger( 'history-size-change', this, this.model, arguments );
}, this );
},
// ------------------------------------------------------------------------ panel rendering
@@ -263,27 +260,28 @@ var CurrentHistoryPanel = _super.extend(
_renderTags : function( $where ){
var panel = this;
// render tags and show/hide based on preferences
_super.prototype._renderTags.call( this, $where );
if( this.preferences.get( 'tagsEditorShown' ) ){
this.tagsEditor.toggle( true );
_super.prototype._renderTags.call( panel, $where );
if( panel.preferences.get( 'tagsEditorShown' ) ){
panel.tagsEditor.toggle( true );
}
// store preference when shown or hidden
this.tagsEditor.on( 'hiddenUntilActivated:shown hiddenUntilActivated:hidden',
panel.listenTo( panel.tagsEditor, 'hiddenUntilActivated:shown hiddenUntilActivated:hidden',
function( tagsEditor ){
panel.preferences.set( 'tagsEditorShown', tagsEditor.hidden );
});
}
);
},
/** In this override, get and set current panel preferences when editor is used */
_renderAnnotation : function( $where ){
var panel = this;
// render annotation and show/hide based on preferences
_super.prototype._renderAnnotation.call( this, $where );
if( this.preferences.get( 'annotationEditorShown' ) ){
this.annotationEditor.toggle( true );
_super.prototype._renderAnnotation.call( panel, $where );
if( panel.preferences.get( 'annotationEditorShown' ) ){
panel.annotationEditor.toggle( true );
}
// store preference when shown or hidden
this.annotationEditor.on( 'hiddenUntilActivated:shown hiddenUntilActivated:hidden',
panel.listenTo( panel.annotationEditor, 'hiddenUntilActivated:shown hiddenUntilActivated:hidden',
function( annotationEditor ){
panel.preferences.set( 'annotationEditorShown', annotationEditor.hidden );
}
@@ -331,12 +329,12 @@ var CurrentHistoryPanel = _super.extend(
_super.prototype._setUpItemViewListeners.call( panel, view );
// use pub-sub to: handle drilldown expansion and collapse
view.on( 'expanded:drilldown', function( v, drilldown ){
panel.listenTo( view, 'expanded:drilldown', function( v, drilldown ){
this._expandDrilldownPanel( drilldown );
}, this );
view.on( 'collapsed:drilldown', function( v, drilldown ){
});
panel.listenTo( view, 'collapsed:drilldown', function( v, drilldown ){
this._collapseDrilldownPanel( drilldown );
}, this );
});
// when content is manipulated, make it the current-content
// view.on( 'visualize', function( v, ev ){
@@ -382,7 +380,7 @@ var CurrentHistoryPanel = _super.extend(
// ........................................................................ external objects/MVC
listenToGalaxy : function( galaxy ){
// TODO: MEM: questionable reference island / closure practice
galaxy.on( 'galaxy_main:load', function( data ){
this.listenTo( galaxy, 'galaxy_main:load', function( data ){
var pathToMatch = data.fullpath,
useToURLRegexMap = {
'display' : /datasets\/([a-f0-9]+)\/display/,
@@ -407,7 +405,7 @@ var CurrentHistoryPanel = _super.extend(
// need to type mangle to go from web route to history contents
hdaId = 'dataset-' + hdaId;
this._setCurrentContentById( hdaId );
}, this );
});
},
//TODO: remove quota meter from panel and remove this
@@ -460,13 +458,13 @@ var CurrentHistoryPanel = _super.extend(
/** Return a string rep of the history
*/
toString : function(){
return 'CurrentHistoryPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'CurrentHistoryView(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
//------------------------------------------------------------------------------ TEMPLATES
CurrentHistoryPanel.prototype.templates = (function(){
CurrentHistoryView.prototype.templates = (function(){
var quotaMsgTemplate = BASE_MVC.wrapTemplate([
'<div class="quota-message errormessage">',
@@ -483,6 +481,6 @@ CurrentHistoryPanel.prototype.templates = (function(){
//==============================================================================
return {
CurrentHistoryPanel : CurrentHistoryPanel
CurrentHistoryView : CurrentHistoryView
};
});
@@ -1,20 +1,21 @@
define([
"mvc/history/history-panel",
"mvc/history/history-view",
"mvc/history/history-contents",
"mvc/dataset/states",
"mvc/history/hda-model",
"mvc/history/hda-li-edit",
"mvc/history/hdca-li-edit",
"mvc/tags",
"mvc/annotations",
"mvc/tag",
"mvc/annotation",
"mvc/collection/list-collection-creator",
"mvc/collection/pair-collection-creator",
"mvc/collection/list-of-pairs-collection-creator",
"ui/fa-icon-button",
"mvc/ui/popup-menu",
"utils/localization"
"utils/localization",
"ui/editable-text",
], function(
HPANEL,
HISTORY_VIEW,
HISTORY_CONTENTS,
STATES,
HDA_MODEL,
@@ -29,22 +30,25 @@ define([
PopupMenu,
_l
){
'use strict';
/* =============================================================================
TODO:
============================================================================= */
var _super = HPANEL.HistoryPanel;
// base class for current-history-panel and used as-is in history/view.mako
var _super = HISTORY_VIEW.HistoryView;
// base class for history-view-edit-current and used as-is in history/view.mako
/** @class Editable View/Controller for the history model.
*
* Allows:
* (everything HistoryPanel allows)
* (everything HistoryView allows)
* changing the name
* displaying and editing tags and annotations
* multi-selection and operations on mulitple content items
*/
var HistoryPanelEdit = _super.extend(
/** @lends HistoryPanelEdit.prototype */{
var HistoryViewEdit = _super.extend(
/** @lends HistoryViewEdit.prototype */{
/** logger used to record this.log messages, commonly set to console */
//logger : console,
@@ -89,7 +93,7 @@ var HistoryPanelEdit = _super.extend(
});
panel.on( 'view:attached view:removed', function(){
panel._renderCounts();
}, panel );
});
},
// ------------------------------------------------------------------------ listeners
@@ -97,19 +101,21 @@ var HistoryPanelEdit = _super.extend(
_setUpCollectionListeners : function(){
_super.prototype._setUpCollectionListeners.call( this );
this.collection.on( 'change:deleted', this._handleHdaDeletionChange, this );
this.collection.on( 'change:visible', this._handleHdaVisibleChange, this );
this.collection.on( 'change:purged', function( model ){
// hafta get the new nice-size w/o the purged model
this.model.fetch();
}, this );
this.listenTo( this.collection, {
'change:deleted': this._handleHdaDeletionChange,
'change:visible': this._handleHdaVisibleChange,
'change:purged' : function( model ){
// hafta get the new nice-size w/o the purged model
this.model.fetch();
}
});
return this;
},
/** listening for history and HDA events */
_setUpModelListeners : function(){
_super.prototype._setUpModelListeners.call( this );
this.model.on( 'change:size', this.updateHistoryDiskSize, this );
this.listenTo( this.model, 'change:size', this.updateHistoryDiskSize );
return this;
},
@@ -120,7 +126,7 @@ var HistoryPanelEdit = _super.extend(
var $newRender = _super.prototype._buildNewRender.call( this );
if( !this.model ){ return $newRender; }
if( Galaxy && Galaxy.currUser && Galaxy.currUser.id && Galaxy.currUser.id === this.model.get( 'user_id' ) ){
if( Galaxy && Galaxy.user && Galaxy.user.id && Galaxy.user.id === this.model.get( 'user_id' ) ){
this._renderTags( $newRender );
this._renderAnnotation( $newRender );
}
@@ -206,7 +212,7 @@ var HistoryPanelEdit = _super.extend(
});
},
/** Set up HistoryPanelEdit js/widget behaviours
/** Set up HistoryViewEdit js/widget behaviours
* In this override, make the name editable
*/
_setUpBehaviors : function( $where ){
@@ -215,8 +221,8 @@ var HistoryPanelEdit = _super.extend(
if( !this.model ){ return; }
// anon users shouldn't have access to any of the following
if( ( !Galaxy.currUser || Galaxy.currUser.isAnonymous() )
|| ( Galaxy.currUser.id !== this.model.get( 'user_id' ) ) ){
if( ( !Galaxy.user || Galaxy.user.isAnonymous() )
|| ( Galaxy.user.id !== this.model.get( 'user_id' ) ) ){
return;
}
@@ -496,16 +502,14 @@ var HistoryPanelEdit = _super.extend(
},
/** */
drop : function( ev ){
//console.warn( 'dataTransfer:', ev.dataTransfer.getData( 'text' ) );
//console.warn( 'dataTransfer:', ev.originalEvent.dataTransfer.getData( 'text' ) );
ev.preventDefault();
//ev.stopPropagation();
ev.dataTransfer.dropEffect = 'move';
//console.debug( 'ev.dataTransfer:', ev.dataTransfer );
var dataTransfer = ev.originalEvent.dataTransfer;
dataTransfer.dropEffect = 'move';
var panel = this,
data = ev.dataTransfer.getData( "text" );
data = dataTransfer.getData( "text" );
try {
data = JSON.parse( data );
@@ -529,12 +533,12 @@ var HistoryPanelEdit = _super.extend(
// ........................................................................ misc
/** Return a string rep of the history */
toString : function(){
return 'HistoryPanelEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'HistoryViewEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
//==============================================================================
return {
HistoryPanelEdit : HistoryPanelEdit
HistoryViewEdit : HistoryViewEdit
};
});
@@ -1,10 +1,9 @@
define([
"mvc/list/list-panel",
"mvc/list/list-view",
"mvc/history/history-model",
"mvc/history/history-contents",
"mvc/history/hda-li",
"mvc/history/hdca-li",
"mvc/collection/collection-panel",
"mvc/user/user-model",
"ui/fa-icon-button",
"mvc/ui/popup-menu",
@@ -12,12 +11,11 @@ define([
"utils/localization",
"ui/search-input"
], function(
LIST_PANEL,
LIST_VIEW,
HISTORY_MODEL,
HISTORY_CONTENTS,
HDA_LI,
HDCA_LI,
COLLECTION_PANEL,
USER,
faIconButton,
PopupMenu,
@@ -25,7 +23,10 @@ define([
_l
){
'use strict';
var logNamespace = 'history';
// ============================================================================
/** session storage for individual history preferences */
var HistoryPrefs = BASE_MVC.SessionStorageModel.extend(
@@ -91,9 +92,9 @@ TODO:
* Does not allow:
* changing the name
*/
var _super = LIST_PANEL.ModelListPanel;
var HistoryPanel = _super.extend(
/** @lends HistoryPanel.prototype */{
var _super = LIST_VIEW.ModelListPanel;
var HistoryView = _super.extend(
/** @lends HistoryView.prototype */{
_logNamespace : logNamespace,
/** class to use for constructing the HDA views */
@@ -254,7 +255,7 @@ var HistoryPanel = _super.extend(
},
// ------------------------------------------------------------------------ browser stored prefs
/** Set up client side storage. Currently PersistanStorage keyed under 'HistoryPanel.<id>'
/** Set up client side storage. Currently PersistanStorage keyed under 'history:<id>'
* @param {Object} initiallyExpanded
* @param {Boolean} show_deleted whether to show deleted contents (overrides stored)
* @param {Boolean} show_hidden
@@ -378,11 +379,13 @@ var HistoryPanel = _super.extend(
//TODO:?? could use 'view:expanded' here?
// maintain a list of items whose bodies are expanded
view.on( 'expanded', function( v ){
panel.storage.addExpanded( v.model );
});
view.on( 'collapsed', function( v ){
panel.storage.removeExpanded( v.model );
panel.listenTo( view, {
'expanded': function( v ){
panel.storage.addExpanded( v.model );
},
'collapsed': function( v ){
panel.storage.removeExpanded( v.model );
}
});
return this;
},
@@ -503,7 +506,7 @@ var HistoryPanel = _super.extend(
//if( xhr.responseText ){
// xhr.responseText = _.escape( xhr.responseText );
//}
var user = Galaxy.currUser,
var user = Galaxy.user,
// add the args (w/ some extra info) into an obj
parsed = {
message : this._bePolite( msg ),
@@ -609,7 +612,7 @@ var HistoryPanel = _super.extend(
// ........................................................................ scrolling
/** Scrolls the panel to show the content sub-view with the given hid.
* @param {Integer} hid the hid of item to scroll into view
* @returns {HistoryPanel} the panel
* @returns {HistoryView} the panel
*/
scrollToHid : function( hid ){
return this.scrollToItem( _.first( this.viewsWhereModel({ hid: hid }) ) );
@@ -618,13 +621,13 @@ var HistoryPanel = _super.extend(
// ........................................................................ misc
/** Return a string rep of the history */
toString : function(){
return 'HistoryPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'HistoryView(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
//------------------------------------------------------------------------------ TEMPLATES
HistoryPanel.prototype.templates = (function(){
HistoryView.prototype.templates = (function(){
var controlsTemplate = BASE_MVC.wrapTemplate([
'<div class="controls">',
@@ -688,6 +691,6 @@ HistoryPanel.prototype.templates = (function(){
//==============================================================================
return {
HistoryPanel: HistoryPanel
HistoryView: HistoryView
};
});
@@ -2,6 +2,9 @@ define([
'utils/graph',
'utils/add-logging'
],function( GRAPH, addLogging ){
'use strict';
// ============================================================================
var _super = GRAPH.Graph;
/** A Directed acyclic Graph built from a history's job data.
@@ -1,12 +1,14 @@
define([
"mvc/history/history-model",
"mvc/history/history-panel-edit",
"mvc/history/history-view-edit",
"mvc/history/copy-dialog",
"mvc/base-mvc",
"utils/ajax-queue",
"ui/mode-button",
"ui/search-input"
], function( HISTORY_MODEL, HPANEL_EDIT, historyCopyDialog, baseMVC, ajaxQueue ){
], function( HISTORY_MODEL, HISTORY_VIEW_EDIT, historyCopyDialog, baseMVC, ajaxQueue ){
'use strict';
var logNamespace = 'history';
/* ==============================================================================
@@ -41,7 +43,7 @@ TODO:
============================================================================== */
/** @class A container for a history panel that renders controls for that history (delete, copy, etc.)
*/
var HistoryPanelColumn = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
var HistoryViewColumn = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
//TODO: extend from panel? (instead of aggregating)
_logNamespace : logNamespace,
@@ -73,7 +75,7 @@ var HistoryPanelColumn = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
}, panelOptions );
//this.log( 'panelOptions:', panelOptions );
//TODO: use current-history-panel for current
var panel = new HPANEL_EDIT.HistoryPanelEdit( panelOptions );
var panel = new HISTORY_VIEW_EDIT.HistoryViewEdit( panelOptions );
panel._renderEmptyMessage = this.__patch_renderEmptyMessage;
return panel;
},
@@ -299,7 +301,7 @@ var HistoryPanelColumn = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
// ------------------------------------------------------------------------ misc
/** String rep */
toString : function(){
return 'HistoryPanelColumn(' + ( this.panel? this.panel : '' ) + ')';
return 'HistoryViewColumn(' + ( this.panel? this.panel : '' ) + ')';
}
});
@@ -505,7 +507,7 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
model : history,
purgeAllowed: Galaxy.config.allow_user_dataset_purge
});
var column = new HistoryPanelColumn( options );
var column = new HistoryViewColumn( options );
if( history.id === this.collection.currentHistoryId ){ column.currentHistory = true; }
this.setUpColumnListeners( column );
if( this.datasetSearch ){
@@ -590,7 +592,7 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
var queue = new ajaxQueue.NamedAjaxQueue();
// need to reverse to better match expected order
// TODO: reconsider order in list-panel._setUpItemViewListeners, dragstart (instead of here)
// TODO: reconsider order in list-view._setUpItemViewListeners, dragstart (instead of here)
toCopy.reverse().forEach( function( content ){
queue.add({
name : 'copy-' + content.id,
@@ -779,13 +781,7 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
close : function( ev ){
//TODO: switch to pushState/router
var destination = '/';
if( Galaxy && Galaxy.options && Galaxy.options.root ){
destination = Galaxy.options.root;
} else if( galaxy_config && galaxy_config.root ){
destination = galaxy_config.root;
}
window.location = destination;
window.location = Galaxy.root;
},
_clickToggleDeletedHistories : function( ev ){
@@ -795,9 +791,9 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
/** Include deleted histories in the collection */
toggleDeletedHistories : function( show ){
if( show ){
window.location = Galaxy.options.root + 'history/view_multiple?include_deleted_histories=True';
window.location = Galaxy.root + 'history/view_multiple?include_deleted_histories=True';
} else {
window.location = Galaxy.options.root + 'history/view_multiple';
window.location = Galaxy.root + 'history/view_multiple';
}
},
@@ -1018,7 +1014,7 @@ var MultiPanelColumns = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
currentColumnDropTargetOff : function(){
var currentColumn = this.columnMap[ this.collection.currentHistoryId ];
if( !currentColumn ){ return; }
currentColumn.panel.dataDropped = HPANEL_EDIT.HistoryPanelEdit.prototype.dataDrop;
currentColumn.panel.dataDropped = HISTORY_VIEW_EDIT.HistoryViewEdit.prototype.dataDrop;
// slight override of dropTargetOff to not erase drop-target-help
currentColumn.panel.dropTarget = false;
currentColumn.panel.$( '.history-drop-target' ).remove();
@@ -1,8 +1,12 @@
define([
"mvc/ui/popup-menu",
"mvc/history/copy-dialog",
"mvc/base-mvc",
"utils/localization"
], function( PopupMenu, BASE_MVC, _l ){
], function( PopupMenu, historyCopyDialog, BASE_MVC, _l ){
'use strict';
// ============================================================================
var menu = [
{
@@ -11,7 +15,7 @@ var menu = [
},
{
html : _l( 'Saved Histories' ),
href : 'history/list'
href : 'history/list',
},
{
html : _l( 'Histories Shared with Me' ),
@@ -19,7 +23,7 @@ var menu = [
},
{
html : _l( 'Current History' ),
html : _l( 'History Actions' ),
header : true,
anon : true
},
@@ -29,32 +33,61 @@ var menu = [
if( Galaxy && Galaxy.currHistoryPanel ){
Galaxy.currHistoryPanel.createNewHistory();
}
}
},
},
{
html : _l( 'Copy History' ),
href : 'history/copy'
},
{
html : _l( 'Copy Datasets' ),
href : 'dataset/copy_datasets'
func : function() {
historyCopyDialog( Galaxy.currHistoryPanel.model )
.done( function(){
Galaxy.currHistoryPanel.loadCurrentHistory();
});
},
},
{
html : _l( 'Share or Publish' ),
href : 'history/sharing'
href : 'history/sharing',
},
{
html : _l( 'Show Structure' ),
href : 'history/display_structured',
anon : true,
},
{
html : _l( 'Extract Workflow' ),
href : 'workflow/build_from_current_history'
href : 'workflow/build_from_current_history',
},
{
html : _l( 'Delete' ),
confirm : _l( 'Really delete the current history?' ),
href : 'history/delete_current',
},
{
html : _l( 'Delete Permanently' ),
confirm : _l( 'Really delete the current history permanently? This cannot be undone.' ),
href : 'history/delete_current?purge=True',
purge : true,
anon : true,
},
{
html : _l( 'Dataset Actions' ),
header : true,
anon : true
},
{
html : _l( 'Copy Datasets' ),
href : 'dataset/copy_datasets',
},
{
html : _l( 'Dataset Security' ),
href : 'root/history_set_default_permissions'
href : 'root/history_set_default_permissions',
},
{
html : _l( 'Resume Paused Jobs' ),
href : 'history/resume_paused_jobs?current=True',
anon : true
anon : true,
},
{
html : _l( 'Collapse Expanded Datasets' ),
@@ -62,7 +95,7 @@ var menu = [
if( Galaxy && Galaxy.currHistoryPanel ){
Galaxy.currHistoryPanel.collapseAll();
}
}
},
},
{
html : _l( 'Unhide Hidden Datasets' ),
@@ -80,7 +113,7 @@ var menu = [
console.error( arguments );
});
}
}
},
},
{
html : _l( 'Delete Hidden Datasets' ),
@@ -99,41 +132,30 @@ var menu = [
console.error( arguments );
});
}
}
},
},
{
html : _l( 'Purge Deleted Datasets' ),
confirm : _l( 'Really delete all deleted datasets permanently? This cannot be undone.' ),
href : 'history/purge_deleted_datasets',
purge : true,
anon : true
anon : true,
},
{
html : _l( 'Downloads' ),
header : true
},
{
html : _l( 'Show Structure' ),
href : 'history/display_structured',
anon : true
},
{
html : _l( 'Export Citations' ),
html : _l( 'Export Tool Citations' ),
href : 'history/citations',
anon : true
anon : true,
},
{
html : _l( 'Export to File' ),
html : _l( 'Export History to File' ),
href : 'history/export_archive?preview=True',
anon : true
},
{
html : _l( 'Delete' ),
confirm : _l( 'Really delete the current history?' ),
href : 'history/delete_current'
},
{
html : _l( 'Delete Permanently' ),
confirm : _l( 'Really delete the current history permanently? This cannot be undone.' ),
href : 'history/delete_current?purge=True',
purge : true,
anon : true
anon : true,
},
{
@@ -142,7 +164,7 @@ var menu = [
},
{
html : _l( 'Import from File' ),
href : 'history/import_archive'
href : 'history/import_archive',
}
];
@@ -160,6 +182,7 @@ function buildMenu( isAnon, purgeAllowed, urlRoot ){
menuOption.href = urlRoot + menuOption.href;
menuOption.target = 'galaxy_main';
}
if( menuOption.confirm ){
menuOption.func = function(){
if( confirm( menuOption.confirm ) ){
@@ -175,8 +198,7 @@ var create = function( $button, options ){
options = options || {};
var isAnon = options.anonymous === undefined? true : options.anonymous,
purgeAllowed = options.purgeAllowed || false,
root = options.root || ( ( Galaxy && Galaxy.options )? Galaxy.options.root: '/' ),
menu = buildMenu( isAnon, purgeAllowed, root );
menu = buildMenu( isAnon, purgeAllowed, Galaxy.root );
//console.debug( 'menu:', menu );
return new PopupMenu( $button, menu );
};
+2 -2
View File
@@ -86,7 +86,7 @@ var Job = Backbone.Model
// ........................................................................ ajax
/** root api url */
urlRoot : (( window.galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' )) + 'api/jobs',
urlRoot : Galaxy.root + 'api/jobs',
//url : function(){ return this.urlRoot; },
// ........................................................................ searching
@@ -115,7 +115,7 @@ var JobCollection = Backbone.Collection
model : Job,
/** root api url */
urlRoot : (( window.galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' )) + 'api/jobs',
urlRoot : Galaxy.root + 'api/jobs',
url : function(){ return this.urlRoot; },
intialize : function( models, options ){
File diff suppressed because it is too large Load Diff
@@ -73,15 +73,15 @@ var FolderView = Backbone.View.extend({
$(".tooltip").remove();
var is_admin = false;
if (Galaxy.currUser){
is_admin = Galaxy.currUser.isAdmin();
}
if (Galaxy.user){
is_admin = Galaxy.user.isAdmin();
}
var template = this.templateFolderPermissions();
this.$el.html(template({folder: this.model, is_admin:is_admin}));
var self = this;
if (this.options.fetched_permissions === undefined){
$.get( ( window.galaxy_config ? galaxy_config.root : '/' ) + "api/folders/" + self.id + "/permissions?scope=current").done(function(fetched_permissions) {
$.get( Galaxy.root + "api/folders/" + self.id + "/permissions?scope=current").done(function(fetched_permissions) {
self.prepareSelectBoxes({fetched_permissions:fetched_permissions});
}).fail(function(){
mod_toastr.error('An error occurred while attempting to fetch folder permissions.');
@@ -98,7 +98,7 @@ var FolderView = Backbone.View.extend({
_serializeRoles : function(role_list){
var selected_roles = [];
for (var i = 0; i < role_list.length; i++) {
selected_roles.push(role_list[i] + ':' + role_list[i]);
selected_roles.push(role_list[i][1] + ':' + role_list[i][0]);
}
return selected_roles;
},
@@ -125,7 +125,7 @@ var FolderView = Backbone.View.extend({
placeholder: 'Click to select a role',
container: self.$el.find('#' + id),
ajax: {
url: ( window.galaxy_config ? galaxy_config.root : '/' ) + "api/folders/" + self.id + "/permissions?scope=available",
url: Galaxy.root + "api/folders/" + self.id + "/permissions?scope=available",
dataType: 'json',
quietMillis: 100,
data: function (term, page) { // page is the one-based page number tracked by Select2
@@ -156,7 +156,7 @@ var FolderView = Backbone.View.extend({
$(element.val().split(",")).each(function() {
var item = this.split(':');
data.push({
id: item[1],
id: item[0],
name: item[1]
});
});
@@ -181,6 +181,9 @@ var FolderView = Backbone.View.extend({
window.prompt("Copy to clipboard: Ctrl+C, Enter", href);
},
/**
* Extract the role ids from Select2 elements's 'data'
*/
_extractIds: function(roles_list){
ids_list = [];
for (var i = roles_list.length - 1; i >= 0; i--) {
@@ -188,16 +191,17 @@ var FolderView = Backbone.View.extend({
};
return ids_list;
},
/**
* Save the permissions for roles entered in the select boxes.
*/
savePermissions: function(event){
var self = this;
var add_ids = this._extractIds(this.addSelectObject.$el.select2('data'));
var manage_ids = this._extractIds(this.manageSelectObject.$el.select2('data'));
var modify_ids = this._extractIds(this.modifySelectObject.$el.select2('data'));
$.post( ( window.galaxy_config ? galaxy_config.root : '/' ) + "api/folders/" + self.id + "/permissions?action=set_permissions", { 'add_ids[]': add_ids, 'manage_ids[]': manage_ids, 'modify_ids[]': modify_ids, } )
$.post( Galaxy.root + "api/folders/" + self.id + "/permissions?action=set_permissions", { 'add_ids[]': add_ids, 'manage_ids[]': manage_ids, 'modify_ids[]': modify_ids, } )
.done(function(fetched_permissions){
//fetch dataset again
self.showPermissions({fetched_permissions:fetched_permissions})
mod_toastr.success('Permissions saved.');
})
@@ -252,7 +256,7 @@ var FolderView = Backbone.View.extend({
var tmpl_array = [];
// CONTAINER START
tmpl_array.push('<div class="library_style_container">');
tmpl_array.push(' <div id="library_toolbar">');
tmpl_array.push(' <a href="#/folders/<%= folder.get("parent_id") %>"><button data-toggle="tooltip" data-placement="top" title="Go back to the parent folder" class="btn btn-default primary-button" type="button"><span class="fa fa-caret-left fa-lg"></span> Parent folder</span></button></a>');
@@ -267,7 +271,7 @@ var FolderView = Backbone.View.extend({
tmpl_array.push('You can assign any number of roles to any of the following permission types. However please read carefully the implications of such actions.');
tmpl_array.push('<% }%>');
tmpl_array.push('</div>');
tmpl_array.push('<div class="dataset_table">');
tmpl_array.push('<h2>Folder permissions</h2>');
@@ -1,5 +1,5 @@
define([
"galaxy.masthead",
"layout/masthead",
"utils/utils",
"libs/toastr",
"mvc/library/library-model",
@@ -102,7 +102,7 @@ var FolderListView = Backbone.View.extend({
upper_folder_id = path[ path.length-2 ][ 0 ];
}
this.$el.html( template( {
this.$el.html( template( {
path: this.folderContainer.attributes.metadata.full_path,
parent_library_id: this.folderContainer.attributes.metadata.parent_library_id,
id: this.options.id,
@@ -178,11 +178,6 @@ var FolderListView = Backbone.View.extend({
var fetched_metadata = this.folderContainer.attributes.metadata;
fetched_metadata.contains_file_or_folder = typeof this.collection.findWhere({type: 'file'}) !== 'undefined' || typeof this.collection.findWhere({type: 'folder'}) !== 'undefined';
Galaxy.libraries.folderToolbarView.configureElements(fetched_metadata);
$('.library-row').hover(function() {
$(this).find('.show_on_hover').show();
}, function () {
$(this).find('.show_on_hover').hide();
});
},
/**
@@ -207,18 +202,12 @@ var FolderListView = Backbone.View.extend({
// model.set('readable_size', this.size_to_string(model.get('file_size')));
//}
model.set('folder_id', this.id);
var rowView = new mod_library_folderrow_view.FolderRowView(model);
var rowView = new mod_library_folderrow_view.FolderRowView({model: model});
// save new rowView to cache
this.rowViews[model.get('id')] = rowView;
this.$el.find('#first_folder_item').after(rowView.el);
$('.library-row').hover(function() {
$(this).find('.show_on_hover').show();
}, function () {
$(this).find('.show_on_hover').hide();
});
},
/**
@@ -226,7 +215,9 @@ var FolderListView = Backbone.View.extend({
* @param {Item or FolderAsModel} model of the view that will be removed
*/
removeOne: function( model ){
this.$el.find( '#' + model.id ).remove();
this.$el.find('tr').filter(function(){
return $(this).data('id') && $(this).data('id') === model.id;
}).remove();
},
/**
@@ -259,8 +250,8 @@ var FolderListView = Backbone.View.extend({
},
/**
* Sorts the underlying collection according to the parameters received.
* Currently supports only sorting by name.
* Sorts the underlying collection according to the parameters received.
* Currently supports only sorting by name.
*/
sortFolder: function(sort_by, order){
console.log('sorting');
@@ -293,13 +284,13 @@ var FolderListView = Backbone.View.extend({
that.makeDarkRow($row);
} else {
that.makeWhiteRow($row);
}
}
});
},
/**
* Check checkbox if user clicks on the whole row or
* on the checkbox itself
/**
* Check checkbox if user clicks on the whole row or
* on the checkbox itself
*/
selectClickedRow : function (event) {
var checkbox = '';
@@ -310,8 +301,8 @@ var FolderListView = Backbone.View.extend({
$row = $(event.target.parentElement.parentElement);
source = 'input';
} else if (event.target.localName === 'td') {
checkbox = $("#" + event.target.parentElement.id).find(':checkbox')[0];
$row = $(event.target.parentElement);
checkbox = $row.find(':checkbox')[0];
source = 'td';
}
if (checkbox.checked){
@@ -374,6 +365,7 @@ var FolderListView = Backbone.View.extend({
tmpl_array.push(' <th class="button_heading"></th>');
tmpl_array.push(' <th style="text-align: center; width: 20px; " title="Check to select all datasets"><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');
tmpl_array.push(' <th><a class="sort-folder-link" title="Click to reverse order" href="#">name</a> <span title="Sorted alphabetically" class="sort-icon fa fa-sort-alpha-<%- order %>"></span></th>');
tmpl_array.push(' <th style="width:25%;">description</th>');
tmpl_array.push(' <th style="width:5%;">data type</th>');
tmpl_array.push(' <th style="width:10%;">size</th>');
tmpl_array.push(' <th style="width:160px;">time updated (UTC)</th>');
@@ -388,6 +380,7 @@ var FolderListView = Backbone.View.extend({
tmpl_array.push(' <td></td>');
tmpl_array.push(' <td></td>');
tmpl_array.push(' <td></td>');
tmpl_array.push(' <td></td>');
tmpl_array.push(' </tr>');
tmpl_array.push(' </tbody>');
@@ -396,7 +389,7 @@ var FolderListView = Backbone.View.extend({
return _.template(tmpl_array.join(''));
}
});
return {
@@ -1,43 +1,51 @@
define([
"galaxy.masthead",
"utils/utils",
"libs/toastr",
"mvc/library/library-model",
"mvc/library/library-dataset-view"],
function(mod_masthead,
mod_utils,
mod_toastr,
function(mod_toastr,
mod_library_model,
mod_library_dataset_view) {
var FolderRowView = Backbone.View.extend({
lastSelectedHistory: '',
events: {
'click .undelete_dataset_btn' : 'undeleteDataset',
'click .undelete_folder_btn' : 'undeleteFolder'
'click .undelete_folder_btn' : 'undeleteFolder',
'click .edit_folder_btn' : 'startModifications',
'click .cancel_folder_btn' : 'cancelModifications',
'click .save_folder_btn' : 'saveModifications',
},
options: {
type: null
defaults: {
type: null,
visibility_config: {
edit_folder_btn: true,
save_folder_btn: false,
cancel_folder_btn: false,
permission_folder_btn: true
},
edit_mode: false
},
initialize : function(folder_item){
this.model = folder_item;
this.render(folder_item);
initialize : function(options){
this.options = _.defaults( options || {}, this.defaults );
this.render(this.options);
},
render: function(folder_item){
render: function(options){
this.options = _.extend( this.options, options );
var folder_item = this.options.model;
var template = null;
if (folder_item.get('type') === 'folder' || folder_item.get('model_class') === 'LibraryFolder'){
this.options.type = 'folder';
this.prepareButtons(folder_item);
if (folder_item.get('deleted')){
template = this.templateRowDeletedFolder();
} else{
} else {
template = this.templateRowFolder();
}
} else if (folder_item.get('type') === 'file' || folder_item.get('model_class') === 'LibraryDatasetDatasetAssociation'){
} else if (folder_item.get('type') === 'file' || folder_item.get('model_class') === 'LibraryDatasetDatasetAssociation' || folder_item.get('model_class') === 'LibraryDataset'){
this.options.type = 'file';
if (folder_item.get('deleted')){
template = this.templateRowDeletedFile();
@@ -48,25 +56,55 @@ var FolderRowView = Backbone.View.extend({
console.error('Unknown library item type found.');
console.error(folder_item.get('type') || folder_item.get('model_class'));
}
this.setElement(template({content_item:folder_item}));
this.setElement(template({content_item: folder_item, edit_mode: this.options.edit_mode, button_config: this.options.visibility_config}));
this.$el.show();
return this;
},
/**
* Modify the visibility of buttons for
* the filling of the row template of a given folder.
*/
prepareButtons: function(folder){
vis_config = this.options.visibility_config;
if (this.options.edit_mode === false){
vis_config.save_folder_btn = false;
vis_config.cancel_folder_btn = false;
if (folder.get('deleted') === true ){
vis_config.edit_folder_btn = false;
vis_config.permission_folder_btn = false;
} else if (folder.get('deleted') === false ) {
vis_config.save_folder_btn = false;
vis_config.cancel_folder_btn = false;
if (folder.get('can_modify') === true){
vis_config.edit_folder_btn = true;
}
if (folder.get('can_manage') === true){
vis_config.permission_folder_btn = true;
}
}
} else if (this.options.edit_mode === true){
vis_config.edit_folder_btn = false;
vis_config.permission_folder_btn = false;
vis_config.save_folder_btn = true;
vis_config.cancel_folder_btn = true;
}
this.options.visibility_config = vis_config;
},
/* Show the page with dataset details. */
showDatasetDetails : function(){
Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: this.id});
},
/**
* Undeletes the dataset on server and renders the row again.
*/
/* Undelete the dataset on server and render the row again. */
undeleteDataset : function(event){
$(".tooltip").hide();
var that = this;
var dataset_id = $(event.target).closest('tr')[0].id;
var dataset_id = $(event.target).closest('tr').data('id');
var dataset = Galaxy.libraries.folderListView.collection.get(dataset_id);
dataset.url = dataset.urlRoot + dataset.id + '?undelete=true';
dataset.destroy({
dataset.destroy({
success : function(model, response){
Galaxy.libraries.folderListView.collection.remove(dataset_id);
var updated_dataset = new mod_library_model.Item(response);
@@ -76,7 +114,7 @@ var FolderRowView = Backbone.View.extend({
var folder_id = that.model.get('folder_id');
window.location='#folders/' + folder_id + '/datasets/' + that.id;
}});
},
},
error : function(model, response){
if (typeof response.responseJSON !== "undefined"){
mod_toastr.error('Dataset was not undeleted. ' + response.responseJSON.err_msg);
@@ -87,13 +125,11 @@ var FolderRowView = Backbone.View.extend({
});
},
/**
* Undeletes the folder on server and renders the row again.
*/
/* Undelete the folder on server and render the row again. */
undeleteFolder : function(event){
$(".tooltip").hide();
var that = this;
var folder_id = $(event.target).closest('tr')[0].id;
var folder_id = $(event.target).closest('tr').data('id');
var folder = Galaxy.libraries.folderListView.collection.get(folder_id);
folder.url = folder.urlRoot + folder.id + '?undelete=true';
folder.destroy({
@@ -103,7 +139,7 @@ var FolderRowView = Backbone.View.extend({
Galaxy.libraries.folderListView.collection.add(updated_folder);
Galaxy.libraries.folderListView.collection.sortByNameAsc();
mod_toastr.success('Folder undeleted.');
},
},
error : function(model, response){
if (typeof response.responseJSON !== "undefined"){
mod_toastr.error('Folder was not undeleted. ' + response.responseJSON.err_msg);
@@ -114,37 +150,128 @@ var FolderRowView = Backbone.View.extend({
});
},
/* User clicked the 'edit' button on row so render the row as editable. */
startModifications: function(){
this.options.edit_mode = true;
this.repaint();
},
/* User clicked the 'cancel' button so render normal row */
cancelModifications: function(){
this.options.edit_mode = false;
this.repaint();
},
saveModifications: function(){
var folder = Galaxy.libraries.folderListView.collection.get(this.$el.data('id'));
var is_changed = false;
var new_name = this.$el.find('.input_folder_name').val();
if (typeof new_name !== 'undefined' && new_name !== folder.get('name') ){
if (new_name.length > 2){
folder.set("name", new_name);
is_changed = true;
} else{
mod_toastr.warning('Folder name has to be at least 3 characters long.');
return;
}
}
var new_description = this.$el.find('.input_folder_description').val();
if (typeof new_description !== 'undefined' && new_description !== folder.get('description') ){
folder.set("description", new_description);
is_changed = true;
}
if (is_changed){
var row_view = this;
folder.save(null, {
patch: true,
success: function(folder) {
row_view.options.edit_mode = false;
row_view.repaint(folder);
mod_toastr.success('Changes to folder saved.');
},
error: function(model, response){
if (typeof response.responseJSON !== "undefined"){
mod_toastr.error(response.responseJSON.err_msg);
} else {
mod_toastr.error('An error occured while attempting to update the folder.');
}
}
});
} else {
this.options.edit_mode = false;
this.repaint(folder);
mod_toastr.info('Nothing has changed.');
}
},
repaint: function(){
/* need to hide manually because of the element removal in setElement
invoked in render() */
$(".tooltip").hide();
/* we need to store the old element to be able to replace it with
new one */
var old_element = this.$el;
/* if user canceled the folder param is undefined,
if user saved and succeeded the updated folder is rendered */
this.render();
old_element.replaceWith(this.$el);
/* now we attach new tooltips to the newly created row element */
this.$el.find("[data-toggle]").tooltip();
},
templateRowFolder: function() {
tmpl_array = [];
tmpl_array.push('<tr class="folder_row light library-row" id="<%- content_item.id %>">');
tmpl_array.push(' <td>');
tmpl_array.push(' <span title="Folder" class="fa fa-folder-o"></span>');
tmpl_array.push(' </td>');
tmpl_array.push(' <td style="text-align: center; "><input style="margin: 0;" type="checkbox"></td>');
tmpl_array.push(' <td>');
tmpl_array.push(' <a href="#folders/<%- content_item.id %>"><%- content_item.get("name") %></a>');
tmpl_array.push(' </td>');
tmpl_array.push(' <td>folder</td>');
tmpl_array.push(' <td></td>');
tmpl_array.push(' <td><%= _.escape(content_item.get("update_time")) %></td>'); // time updated
tmpl_array.push(' <td>');
tmpl_array.push(' <% if (content_item.get("can_manage")) { %><a href="#/folders/<%- content_item.id %>/permissions"><button data-toggle="tooltip" data-placement="top" class="primary-button btn-xs permissions-folder-btn show_on_hover" title="Manage permissions" style="display:none;"><span class="fa fa-group"></span></button></a><% } %>');
tmpl_array.push(' </td>');
tmpl_array.push('</tr>');
return _.template(tmpl_array.join(''));
return _.template([
'<tr class="folder_row light library-row" data-id="<%- content_item.id %>">',
'<td>',
'<span title="Folder" class="fa fa-folder-o"></span>',
'</td>',
'<td style="text-align: center; "><input style="margin: 0;" type="checkbox"></td>',
'<% if(!edit_mode) { %>',
'<td>',
'<a href="#folders/<%- content_item.id %>"><%- content_item.get("name") %></a>',
'</td>',
'<td>',
'<%- content_item.get("description") %>',
'</td>',
'<% } else if(edit_mode){ %>',
'<td><textarea rows="4" class="form-control input_folder_name" placeholder="name" ><%- content_item.get("name") %></textarea></td>',
'<td><textarea rows="4" class="form-control input_folder_description" placeholder="description" ><%- content_item.get("description") %></textarea></td>',
'<% } %>',
'<td>folder</td>',
'<td></td>',
'<td>',
'<%= _.escape(content_item.get("update_time")) %>',
'</td>',
'<td>',
'<% if(edit_mode) { %>', // start edit mode
'<button data-toggle="tooltip" data-placement="top" title="Save changes" class="primary-button btn-xs save_folder_btn" type="button" style="<% if(button_config.save_folder_btn === false) { print("display:none;") } %>"><span class="fa fa-floppy-o"> Save</span></button>',
'<button data-toggle="tooltip" data-placement="top" title="Discard changes" class="primary-button btn-xs cancel_folder_btn" type="button" style="<% if(button_config.cancel_folder_btn === false) { print("display:none;") } %>"><span class="fa fa-times"> Cancel</span></button>',
'<% } else if (!edit_mode){%>', // start no edit mode
'<button data-toggle="tooltip" data-placement="top" title="Modify \'<%- content_item.get("name") %>\'" class="primary-button btn-xs edit_folder_btn" type="button" style="<% if(button_config.edit_folder_btn === false) { print("display:none;") } %>">',
'<span class="fa fa-pencil"></span>',
'</button>',
'<a href="#/folders/<%- content_item.id %>/permissions">',
'<button data-toggle="tooltip" data-placement="top" class="primary-button btn-xs permission_folder_btn" title="Manage \'<%- content_item.get("name") %>\'" style="<% if(button_config.permission_folder_btn === false) { print("display:none;") } %>">',
'<span class="fa fa-group"></span>',
'</button>',
'</a>',
'<% } %>', //end no edit mode
'</td>',
'</tr>'
].join(''));
},
templateRowFile: function(){
tmpl_array = [];
tmpl_array.push('<tr class="dataset_row light library-row" id="<%- content_item.id %>">');
tmpl_array.push('<tr class="dataset_row light library-row" data-id="<%- content_item.id %>">');
tmpl_array.push(' <td>');
tmpl_array.push(' <span title="Dataset" class="fa fa-file-o"></span>');
tmpl_array.push(' </td>');
tmpl_array.push(' <td style="text-align: center; "><input style="margin: 0;" type="checkbox"></td>');
tmpl_array.push(' <td><a href="#folders/<%- content_item.get("folder_id") %>/datasets/<%- content_item.id %>" class="library-dataset"><%- content_item.get("name") %><a></td>'); // dataset
tmpl_array.push(' <td><%- content_item.get("message") %></td>');
tmpl_array.push(' <td><%= _.escape(content_item.get("file_ext")) %></td>'); // data type
tmpl_array.push(' <td><%= _.escape(content_item.get("file_size")) %></td>'); // size
tmpl_array.push(' <td><%= _.escape(content_item.get("update_time")) %></td>'); // time updated
@@ -152,26 +279,27 @@ var FolderRowView = Backbone.View.extend({
tmpl_array.push(' <% if (content_item.get("is_unrestricted")) { %><span data-toggle="tooltip" data-placement="top" title="Unrestricted dataset" style="color:grey;" class="fa fa-globe fa-lg"></span><% } %>');
tmpl_array.push(' <% if (content_item.get("is_private")) { %><span data-toggle="tooltip" data-placement="top" title="Private dataset" style="color:grey;" class="fa fa-key fa-lg"></span><% } %>');
tmpl_array.push(' <% if ((content_item.get("is_unrestricted") === false) && (content_item.get("is_private") === false)) { %><span data-toggle="tooltip" data-placement="top" title="Restricted dataset" style="color:grey;" class="fa fa-shield fa-lg"></span><% } %>');
tmpl_array.push(' <% if (content_item.get("can_manage")) { %><a href="#folders/<%- content_item.get("folder_id") %>/datasets/<%- content_item.id %>/permissions"><button data-toggle="tooltip" data-placement="top" class="primary-button btn-xs permissions-dataset-btn show_on_hover" title="Manage permissions" style="display:none;"><span class="fa fa-group"></span></button></a><% } %>');
tmpl_array.push(' <% if (content_item.get("can_manage")) { %><a href="#folders/<%- content_item.get("folder_id") %>/datasets/<%- content_item.id %>/permissions"><button data-toggle="tooltip" data-placement="top" class="primary-button btn-xs permissions-dataset-btn" title="Manage permissions"><span class="fa fa-group"></span></button></a><% } %>');
tmpl_array.push(' </td>');
tmpl_array.push('</tr>');
return _.template(tmpl_array.join(''));
},
},
templateRowDeletedFile: function(){
tmpl_array = [];
tmpl_array.push('<tr class="active deleted_dataset library-row" id="<%- content_item.id %>">');
tmpl_array.push('<tr class="active deleted_dataset library-row" data-id="<%- content_item.id %>">');
tmpl_array.push(' <td>');
tmpl_array.push(' <span title="Dataset" class="fa fa-file-o"></span>');
tmpl_array.push(' </td>');
tmpl_array.push(' <td></td>');
tmpl_array.push(' <td style="color:grey;"><%- content_item.get("name") %></td>'); // dataset
tmpl_array.push(' <td><%- content_item.get("message") %></td>');
tmpl_array.push(' <td><%= _.escape(content_item.get("file_ext")) %></td>'); // data type
tmpl_array.push(' <td><%= _.escape(content_item.get("file_size")) %></td>'); // size
tmpl_array.push(' <td><%= _.escape(content_item.get("update_time")) %></td>'); // time updated
tmpl_array.push(' <td><span data-toggle="tooltip" data-placement="top" title="Marked deleted" style="color:grey;" class="fa fa-ban fa-lg"> </span><button data-toggle="tooltip" data-placement="top" title="Undelete <%- content_item.get("name") %>" class="primary-button btn-xs undelete_dataset_btn show_on_hover" type="button" style="display:none; margin-left:1em;"><span class="fa fa-unlock"> Undelete</span></button></td>');
tmpl_array.push(' <td><span data-toggle="tooltip" data-placement="top" title="Marked deleted" style="color:grey;" class="fa fa-ban fa-lg"> </span><button data-toggle="tooltip" data-placement="top" title="Undelete <%- content_item.get("name") %>" class="primary-button btn-xs undelete_dataset_btn" type="button" style="margin-left:1em;"><span class="fa fa-unlock"> Undelete</span></button></td>');
tmpl_array.push('</tr>');
return _.template(tmpl_array.join(''));
@@ -180,7 +308,7 @@ var FolderRowView = Backbone.View.extend({
templateRowDeletedFolder: function(){
tmpl_array = [];
tmpl_array.push('<tr class="active folder_row light library-row" id="<%- content_item.id %>">');
tmpl_array.push('<tr class="active deleted_folder light library-row" data-id="<%- content_item.id %>">');
tmpl_array.push(' <td>');
tmpl_array.push(' <span title="Folder" class="fa fa-folder-o"></span>');
tmpl_array.push(' </td>');
@@ -188,15 +316,16 @@ var FolderRowView = Backbone.View.extend({
tmpl_array.push(' <td style="color:grey;">');
tmpl_array.push(' <%- content_item.get("name") %>');
tmpl_array.push(' </td>');
tmpl_array.push(' <td><%- content_item.get("description") %></td>');
tmpl_array.push(' <td>folder</td>');
tmpl_array.push(' <td></td>');
tmpl_array.push(' <td><%= _.escape(content_item.get("update_time")) %></td>'); // time updated
tmpl_array.push(' <td><span data-toggle="tooltip" data-placement="top" title="Marked deleted" style="color:grey;" class="fa fa-ban fa-lg"> </span><button data-toggle="tooltip" data-placement="top" title="Undelete <%- content_item.get("name") %>" class="primary-button btn-xs undelete_folder_btn show_on_hover" type="button" style="display:none; margin-left:1em;"><span class="fa fa-unlock"> Undelete</span></button></td>');
tmpl_array.push(' <td><span data-toggle="tooltip" data-placement="top" title="Marked deleted" style="color:grey;" class="fa fa-ban fa-lg"> </span><button data-toggle="tooltip" data-placement="top" title="Undelete <%- content_item.get("name") %>" class="primary-button btn-xs undelete_folder_btn" type="button" style="margin-left:1em;"><span class="fa fa-unlock"> Undelete</span></button></td>');
tmpl_array.push('</tr>');
return _.template(tmpl_array.join(''));
}
});
return {
@@ -1,5 +1,5 @@
define([
"galaxy.masthead",
"layout/masthead",
"utils/utils",
"libs/toastr",
"mvc/library/library-model",
@@ -19,8 +19,8 @@ var FolderToolbarView = Backbone.View.extend({
'click #toolbtn_create_folder' : 'createFolderFromModal',
'click #toolbtn_bulk_import' : 'modalBulkImport',
'click #include_deleted_datasets_chk' : 'checkIncludeDeleted',
'click #toolbtn_show_libinfo' : 'showLibInfo',
'click #toolbtn_bulk_delete' : 'deleteSelectedDatasets',
'click #toolbtn_bulk_delete' : 'deleteSelectedItems',
'click .toolbtn-show-locinfo' : 'showLocInfo',
'click #page_size_prompt' : 'showPageSizePrompt'
},
@@ -63,7 +63,7 @@ var FolderToolbarView = Backbone.View.extend({
' to set your data to the format you think it should be.' +
' You can also upload compressed files, which will automatically be decompressed.'
},
// genomes
list_genomes : [],
@@ -82,9 +82,9 @@ var FolderToolbarView = Backbone.View.extend({
is_anonym: true,
mutiple_add_dataset_options: false
}
if (Galaxy.currUser){
template_defaults.is_admin = Galaxy.currUser.isAdmin();
template_defaults.is_anonym = Galaxy.currUser.isAnonymous();
if (Galaxy.user){
template_defaults.is_admin = Galaxy.user.isAdmin();
template_defaults.is_anonym = Galaxy.user.isAnonymous();
if ( Galaxy.config.user_library_import_dir !== null || Galaxy.config.allow_library_path_paste !== false || Galaxy.config.library_import_dir !== null ){
template_defaults.mutiple_add_dataset_options = true;
}
@@ -99,7 +99,7 @@ var FolderToolbarView = Backbone.View.extend({
renderPaginator: function( options ){
this.options = _.extend( this.options, options );
var paginator_template = this.templatePaginator();
this.$el.find( '#folder_paginator' ).html( paginator_template({
this.$el.find( '#folder_paginator' ).html( paginator_template({
id: this.options.id,
show_page: parseInt( this.options.show_page ),
page_count: parseInt( this.options.page_count ),
@@ -117,8 +117,8 @@ var FolderToolbarView = Backbone.View.extend({
$('.add-library-items').hide();
}
if (this.options.contains_file_or_folder === true){
if (Galaxy.currUser){
if (!Galaxy.currUser.isAnonymous()){
if (Galaxy.user){
if (!Galaxy.user.isAnonymous()){
$('.logged-dataset-manipulation').show();
$('.dataset-manipulation').show();
} else {
@@ -163,7 +163,7 @@ var FolderToolbarView = Backbone.View.extend({
var folder = new mod_library_model.FolderAsModel();
url_items = Backbone.history.fragment.split('/');
current_folder_id = url_items[url_items.length-1];
folder.url = folder.urlRoot + '/' + current_folder_id ;
folder.url = folder.urlRoot + current_folder_id ;
folder.save(folderDetails, {
success: function (folder) {
@@ -252,10 +252,10 @@ var FolderToolbarView = Backbone.View.extend({
var dataset_ids = [];
var folder_ids = [];
$('#folder_table').find(':checked').each(function(){
if (this.parentElement.parentElement.id !== '' && this.parentElement.parentElement.classList.contains('dataset_row') ) {
dataset_ids.push(this.parentElement.parentElement.id);
} else if (this.parentElement.parentElement.id !== '' && this.parentElement.parentElement.classList.contains('folder_row') ) {
folder_ids.push(this.parentElement.parentElement.id);
if ($(this.parentElement.parentElement).data('id') !== '' && this.parentElement.parentElement.classList.contains('dataset_row') ) {
dataset_ids.push($(this.parentElement.parentElement).data('id'));
} else if ($(this.parentElement.parentElement).data('id') !== '' && this.parentElement.parentElement.classList.contains('folder_row') ) {
folder_ids.push($(this.parentElement.parentElement).data('id'));
}
});
// prepare the dataset objects to be imported
@@ -281,9 +281,9 @@ var FolderToolbarView = Backbone.View.extend({
}
this.initChainCallControl( { length: datasets_to_import.length, action: 'to_history', history_name: history_name } );
// set the used history as current so user will see the last one
// set the used history as current so user will see the last one
// that he imported into in the history panel on the 'analysis' page
jQuery.getJSON( galaxy_config.root + 'history/set_as_current?id=' + history_id );
jQuery.getJSON( Galaxy.root + 'history/set_as_current?id=' + history_id );
this.chainCallImportingIntoHistory( datasets_to_import, history_name );
},
@@ -306,13 +306,13 @@ var FolderToolbarView = Backbone.View.extend({
var dataset_ids = [];
var folder_ids = [];
$( '#folder_table' ).find( ':checked' ).each( function(){
if ( this.parentElement.parentElement.id !== '' && this.parentElement.parentElement.classList.contains('dataset_row') ) {
dataset_ids.push( this.parentElement.parentElement.id );
} else if ( this.parentElement.parentElement.id !== '' && this.parentElement.parentElement.classList.contains('folder_row') ) {
folder_ids.push( this.parentElement.parentElement.id );
if ( $(this.parentElement.parentElement).data('id') !== '' && this.parentElement.parentElement.classList.contains('dataset_row') ) {
dataset_ids.push( $(this.parentElement.parentElement).data('id') );
} else if ( $(this.parentElement.parentElement).data('id') !== '' && this.parentElement.parentElement.classList.contains('folder_row') ) {
folder_ids.push( $(this.parentElement.parentElement).data('id') );
}
} );
var url = ( window.galaxy_config ? galaxy_config.root : '/' ) + 'api/libraries/datasets/download/' + format;
var url = Galaxy.root + 'api/libraries/datasets/download/' + format;
var data = { 'ld_ids' : dataset_ids, 'folder_ids' : folder_ids };
this.processDownload( url, data, 'get' );
},
@@ -360,7 +360,7 @@ var FolderToolbarView = Backbone.View.extend({
Galaxy.libraries.library_router.back();
}
});
// user should always have a history, even anonymous user
if (self.histories.models.length > 0){
self.fetchAndDisplayHistoryContents(self.histories.models[0].id);
@@ -393,7 +393,7 @@ var FolderToolbarView = Backbone.View.extend({
// TODO: should not trigger routes outside of the router
Galaxy.libraries.library_router.navigate( 'folders/' + that.id, { trigger: true } );
}
});
});
this.renderSelectBoxes();
},
@@ -404,7 +404,7 @@ var FolderToolbarView = Backbone.View.extend({
fetchExtAndGenomes: function(){
var that = this;
mod_utils.get({
url : ( window.galaxy_config ? galaxy_config.root : '/' ) + "api/datatypes?extension_only=False",
url : Galaxy.root + "api/datatypes?extension_only=False",
success : function( datatypes ) {
for (key in datatypes) {
that.list_extensions.push({
@@ -421,8 +421,8 @@ var FolderToolbarView = Backbone.View.extend({
}
});
mod_utils.get({
url: ( window.galaxy_config ? galaxy_config.root : '/' ) + "api/genomes",
success: function( genomes ) {
url : Galaxy.root + "api/genomes",
success : function( genomes ) {
for ( key in genomes ) {
that.list_genomes.push({
id : genomes[key][1],
@@ -439,7 +439,7 @@ var FolderToolbarView = Backbone.View.extend({
renderSelectBoxes: function(){
// This won't work properly unlesss we already have the data fetched.
// See this.fetchExtAndGenomes()
// TODO switch to common resources:
// TODO switch to common resources:
// https://trello.com/c/dIUE9YPl/1933-ui-common-resources-and-data-into-galaxy-object
var that = this;
this.select_genome = new mod_select.View( {
@@ -469,7 +469,7 @@ var FolderToolbarView = Backbone.View.extend({
title : 'Please select folders or files',
body : template_modal({}),
buttons : {
'Import' : function() {
'Import' : function() {
that.importFromJstreePath( that, options );
},
'Close' : function() {
@@ -503,7 +503,7 @@ var FolderToolbarView = Backbone.View.extend({
that.renderJstree( options );
}
}
);
);
},
/**
@@ -518,9 +518,9 @@ var FolderToolbarView = Backbone.View.extend({
var target = options.source || 'userdir';
var disabled_jstree_element = this.options.disabled_jstree_element;
this.jstree = new mod_library_model.Jstree();
this.jstree.url = this.jstree.urlRoot +
'?target=' + target +
'&format=jstree' +
this.jstree.url = this.jstree.urlRoot +
'?target=' + target +
'&format=jstree' +
'&disable=' + disabled_jstree_element;
this.jstree.fetch({
success: function(model, response){
@@ -550,7 +550,11 @@ var FolderToolbarView = Backbone.View.extend({
},
error: function(model, response){
if (typeof response.responseJSON !== "undefined"){
mod_toastr.error(response.responseJSON.err_msg);
if (response.responseJSON.err_code === 404001){
mod_toastr.warning(response.responseJSON.err_msg);
} else{
mod_toastr.error(response.responseJSON.err_msg);
}
} else {
mod_toastr.error('An error ocurred.');
}
@@ -583,8 +587,8 @@ var FolderToolbarView = Backbone.View.extend({
};
this.initChainCallControl( { length: valid_paths.length, action: 'adding_datasets' } );
this.chainCallImportingFolders( { paths: valid_paths,
preserve_dirs: preserve_dirs,
link_data: link_data,
preserve_dirs: preserve_dirs,
link_data: link_data,
source: 'admin_path',
file_type: file_type,
dbkey: dbkey } );
@@ -626,9 +630,9 @@ var FolderToolbarView = Backbone.View.extend({
/**
* Take the selected items from the jstree, create a request queue
* and send them one by one to the server for importing into
* the current folder.
*
* and send them one by one to the server for importing into
* the current folder.
*
* jstree.js has to be loaded before
* @see renderJstree
*/
@@ -653,8 +657,8 @@ var FolderToolbarView = Backbone.View.extend({
if ( selection_type === 'folder' ){
var full_source = options.source + '_folder';
this.chainCallImportingFolders( { paths: paths,
preserve_dirs: preserve_dirs,
link_data: link_data,
preserve_dirs: preserve_dirs,
link_data: link_data,
source: full_source,
file_type: file_type,
dbkey: dbkey } );
@@ -707,7 +711,7 @@ var FolderToolbarView = Backbone.View.extend({
for ( var i = history_dataset_ids.length - 1; i >= 0; i-- ) {
history_dataset_id = history_dataset_ids[i];
var folder_item = new mod_library_model.Item();
folder_item.url = ( window.galaxy_config ? galaxy_config.root : '/' ) + 'api/folders/' + this.options.id + '/contents';
folder_item.url = Galaxy.root + 'api/folders/' + this.options.id + '/contents';
folder_item.set( { 'from_hda_id':history_dataset_id } );
hdas_to_add.push( folder_item );
}
@@ -767,7 +771,7 @@ var FolderToolbarView = Backbone.View.extend({
}
return true;
}
var promise = $.when( $.post( ( window.galaxy_config ? galaxy_config.root : '/' ) + 'api/libraries/datasets?encoded_folder_id=' + that.id +
var promise = $.when( $.post( Galaxy.root + 'api/libraries/datasets?encoded_folder_id=' + that.id +
'&source=' + options.source +
'&path=' + popped_item +
'&file_type=' + options.file_type +
@@ -789,7 +793,7 @@ var FolderToolbarView = Backbone.View.extend({
* @param {array} paths paths relative to Galaxy root folder
* @param {boolean} preserve_dirs indicates whether to preserve folder structure
* @param {boolean} link_data copy files to Galaxy or link instead
* @param {str} source string representing what type of folder
* @param {str} source string representing what type of folder
* is the source of import
*/
chainCallImportingFolders: function( options ){
@@ -806,7 +810,7 @@ var FolderToolbarView = Backbone.View.extend({
}
return true;
}
var promise = $.when( $.post( ( window.galaxy_config ? galaxy_config.root : '/' ) + 'api/libraries/datasets?encoded_folder_id=' + that.id +
var promise = $.when( $.post( Galaxy.root + 'api/libraries/datasets?encoded_folder_id=' + that.id +
'&source=' + options.source +
'&path=' + popped_item +
'&preserve_dirs=' + options.preserve_dirs +
@@ -825,7 +829,7 @@ var FolderToolbarView = Backbone.View.extend({
},
/**
* Take the array of hdas and create a request for each.
* Take the array of hdas and create a request for each.
* Call them in chain and update progress bar in between each.
* @param {array} hdas_set array of empty hda objects
*/
@@ -859,11 +863,13 @@ var FolderToolbarView = Backbone.View.extend({
},
/**
* Take the array of lddas, create request for each and
* Take the array of lddas, create request for each and
* call them in chain. Update progress bar in between each.
* @param {array} lddas_set array of lddas to delete
*/
chainCallDeletingItems: function( items_to_delete ){
console.log('chaincall');
console.log(items_to_delete);
var self = this;
this.deleted_items = new mod_library_model.Folder();
var popped_item = items_to_delete.pop();
@@ -894,6 +900,8 @@ var FolderToolbarView = Backbone.View.extend({
console.error('Unknown library item type found.');
console.error(item.type || item.model_class);
}
console.log('updated item')
console.log(updated_item);
Galaxy.libraries.folderListView.collection.add( updated_item );
}
self.chainCallDeletingItems( items_to_delete );
@@ -917,9 +925,9 @@ var FolderToolbarView = Backbone.View.extend({
},
/**
* Deletes the selected datasets. Atomic. One by one.
* Delete the selected items. Atomic. One by one.
*/
deleteSelectedDatasets: function(){
deleteSelectedItems: function(){
var checkedValues = $('#folder_table').find(':checked');
if(checkedValues.length === 0){
mod_toastr.info('You must select at least one dataset for deletion.');
@@ -941,11 +949,11 @@ var FolderToolbarView = Backbone.View.extend({
var dataset_ids = [];
var folder_ids = [];
checkedValues.each(function(){
if (this.parentElement.parentElement.id !== '') {
if (this.parentElement.parentElement.id.substring(0,1) == 'F'){
folder_ids.push(this.parentElement.parentElement.id);
if ($(this.parentElement.parentElement).data('id') !== '') {
if ($(this.parentElement.parentElement).data('id').substring(0,1) == 'F'){
folder_ids.push($(this.parentElement.parentElement).data('id'));
} else {
dataset_ids.push(this.parentElement.parentElement.id);
dataset_ids.push($(this.parentElement.parentElement).data('id'));
}
}
});
@@ -953,7 +961,7 @@ var FolderToolbarView = Backbone.View.extend({
var items_total = dataset_ids.length + folder_ids.length
this.progressStep = 100 / items_total;
this.progress = 0;
// prepare the dataset items to be added
var items_to_delete = [];
for (var i = dataset_ids.length - 1; i >= 0; i--) {
@@ -964,6 +972,7 @@ var FolderToolbarView = Backbone.View.extend({
var folder = new mod_library_model.FolderAsModel({id:folder_ids[i]});
items_to_delete.push(folder);
}
console.log(items_to_delete);
this.options.chain_call_control.total_number = items_total.length;
// call the recursive function to call ajax one after each other (request FIFO queue)
@@ -972,18 +981,17 @@ var FolderToolbarView = Backbone.View.extend({
},
showLibInfo: function(){
var library_id = Galaxy.libraries.folderListView.folderContainer.attributes.metadata.parent_library_id;
showLocInfo: function(){
var library = null;
var that = this;
if (Galaxy.libraries.libraryListView !== null){
library = Galaxy.libraries.libraryListView.collection.get(library_id);
this.showLibInfoModal(library);
library = Galaxy.libraries.libraryListView.collection.get(this.options.parent_library_id);
this.showLocInfoModal(library);
} else {
library = new mod_library_model.Library({id: library_id});
library = new mod_library_model.Library({id: this.options.parent_library_id});
library.fetch({
success: function(){
that.showLibInfoModal(library);
that.showLocInfoModal(library);
},
error: function(model, response){
if (typeof response.responseJSON !== "undefined"){
@@ -996,13 +1004,14 @@ var FolderToolbarView = Backbone.View.extend({
}
},
showLibInfoModal: function(library){
var template = this.templateLibInfoInModal();
showLocInfoModal: function(library){
var that = this;
var template = this.templateLocInfoInModal();
this.modal = Galaxy.modal;
this.modal.show({
closing_events : true,
title : 'Library Information',
body : template({library:library}),
title : 'Location Information',
body : template({library: library, options: that.options}),
buttons : {
'Close' : function() {Galaxy.modal.hide();}
}
@@ -1017,7 +1026,7 @@ var FolderToolbarView = Backbone.View.extend({
case "importdir":
this.importFilesFromGalaxyFolderModal( { source: 'importdir' } );
break;
case "path":
case "path":
this.importFilesFromPathModal();
break;
case "userdir":
@@ -1100,8 +1109,8 @@ var FolderToolbarView = Backbone.View.extend({
tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');
tmpl_array.push(' </ul>');
tmpl_array.push(' </div>');
tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Mark selected datasets deleted" id="toolbtn_bulk_delete" class="primary-button logged-dataset-manipulation" style="margin-left: 0.5em; display:none; " type="button"><span class="fa fa-times"></span> Delete</button>');
tmpl_array.push(' <button data-id="<%- id %>" data-toggle="tooltip" data-placement="top" title="Show library information" id="toolbtn_show_libinfo" class="primary-button" style="margin-left: 0.5em;" type="button"><span class="fa fa-info-circle"></span> Library Info</button>');
tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Mark selected items deleted" id="toolbtn_bulk_delete" class="primary-button logged-dataset-manipulation" style="margin-left: 0.5em; display:none; " type="button"><span class="fa fa-times"></span> Delete</button>');
tmpl_array.push(' <button data-id="<%- id %>" data-toggle="tooltip" data-placement="top" title="Show location information" class="primary-button toolbtn-show-locinfo" style="margin-left: 0.5em;" type="button"><span class="fa fa-info-circle"></span> Location Info</button>');
tmpl_array.push(' <span class="help-button" data-toggle="tooltip" data-placement="top" title="Visit Libraries Wiki"><a href="https://wiki.galaxyproject.org/DataLibraries/screen/FolderContents" target="_blank"><button class="primary-button" type="button"><span class="fa fa-question-circle"></span> Help</button></a></span>');
tmpl_array.push(' </div>');
tmpl_array.push('</form>');
@@ -1115,21 +1124,67 @@ var FolderToolbarView = Backbone.View.extend({
return _.template(tmpl_array.join(''));
},
templateLibInfoInModal: function(){
tmpl_array = [];
tmpl_array.push('<div id="lif_info_modal">');
tmpl_array.push('<h2>Library name:</h2>');
tmpl_array.push('<p><%- library.get("name") %></p>');
tmpl_array.push('<h3>Library description:</h3>');
tmpl_array.push('<p><%- library.get("description") %></p>');
tmpl_array.push('<h3>Library synopsis:</h3>');
tmpl_array.push('<p><%- library.get("synopsis") %></p>');
tmpl_array.push('<p data-toggle="tooltip" data-placement="top" title="<%- library.get("create_time") %>">created <%- library.get("create_time_pretty") %></p>');
tmpl_array.push('</div>');
return _.template(tmpl_array.join(''));
templateLocInfoInModal: function(){
return _.template([
'<div>',
'<table class="grid table table-condensed">',
'<thead>',
'<th style="width: 25%;">library</th>',
'<th></th>',
'</thead>',
'<tbody>',
'<tr>',
'<td>name</td>',
'<td><%- library.get("name") %></td>',
'</tr>',
'<% if(library.get("description") !== "") { %>',
'<tr>',
'<td>description</td>',
'<td><%- library.get("description") %></td>',
'</tr>',
'<% } %>',
'<% if(library.get("synopsis") !== "") { %>',
'<tr>',
'<td>synopsis</td>',
'<td><%- library.get("synopsis") %></td>',
'</tr>',
'<% } %>',
'<% if(library.get("create_time_pretty") !== "") { %>',
'<tr>',
'<td>created</td>',
'<td><span title="<%- library.get("create_time") %>"><%- library.get("create_time_pretty") %></span></td>',
'</tr>',
'<% } %>',
'<tr>',
'<td>id</td>',
'<td><%- library.get("id") %></td>',
'</tr>',
'</tbody>',
'</table>',
'<table class="grid table table-condensed">',
'<thead>',
'<th style="width: 25%;">folder</th>',
'<th></th>',
'</thead>',
'<tbody>',
'<tr>',
'<td>name</td>',
'<td><%- options.folder_name %></td>',
'</tr>',
'<% if(options.folder_description !== "") { %>',
'<tr>',
'<td>description</td>',
'<td><%- options.folder_description %></td>',
'</tr>',
'<% } %>',
'<tr>',
'<td>id</td>',
'<td><%- options.id %></td>',
'</tr>',
'</tbody>',
'</table>',
'</div>'
].join(''));
},
templateNewFolderInModal: function(){
@@ -1215,7 +1270,7 @@ var FolderToolbarView = Backbone.View.extend({
tmpl_array.push('<div class="alert alert-info jstree-files-message">All files you select will be imported into the current folder.</div>');
tmpl_array.push('<div class="alert alert-info jstree-folders-message" style="display:none;">All files within the selected folders and their subfolders will be imported into the current folder.</div>');
tmpl_array.push('<div style="margin-bottom:1em;">');
tmpl_array.push('<label class="radio-inline">');
tmpl_array.push(' <input title="Switch to selecting files" type="radio" name="jstree-radio" value="jstree-disable-folders" checked="checked"> Files');
@@ -79,15 +79,15 @@ var LibraryView = Backbone.View.extend({
}
}
var is_admin = false;
if (Galaxy.currUser){
is_admin = Galaxy.currUser.isAdmin();
}
if (Galaxy.user){
is_admin = Galaxy.user.isAdmin();
}
var template = this.templateLibraryPermissions();
this.$el.html(template({library: this.model, is_admin:is_admin}));
var self = this;
if (this.options.fetched_permissions === undefined){
$.get( ( window.galaxy_config ? galaxy_config.root : '/' ) + "api/libraries/" + self.id + "/permissions?scope=current").done(function(fetched_permissions) {
$.get( Galaxy.root + "api/libraries/" + self.id + "/permissions?scope=current").done(function(fetched_permissions) {
self.prepareSelectBoxes({fetched_permissions:fetched_permissions});
}).fail(function(){
mod_toastr.error('An error occurred while attempting to fetch library permissions.');
@@ -134,7 +134,7 @@ var LibraryView = Backbone.View.extend({
placeholder: 'Click to select a role',
container: self.$el.find('#' + id),
ajax: {
url: ( window.galaxy_config ? galaxy_config.root : '/' ) + "api/libraries/" + self.id + "/permissions?scope=available&is_library_access=" + is_library_access,
url: Galaxy.root + "api/libraries/" + self.id + "/permissions?scope=available&is_library_access=" + is_library_access,
dataType: 'json',
quietMillis: 100,
data: function (term, page) { // page is the one-based page number tracked by Select2
@@ -193,7 +193,7 @@ var LibraryView = Backbone.View.extend({
makeDatasetPrivate: function(){
var self = this;
$.post( ( window.galaxy_config ? galaxy_config.root : '/' ) + "api/libraries/datasets/" + self.id + "/permissions?action=make_private").done(function(fetched_permissions) {
$.post( Galaxy.root + "api/libraries/datasets/" + self.id + "/permissions?action=make_private").done(function(fetched_permissions) {
self.model.set({is_unrestricted:false});
self.showPermissions({fetched_permissions:fetched_permissions})
mod_toastr.success('The dataset is now private to you.');
@@ -204,7 +204,7 @@ var LibraryView = Backbone.View.extend({
removeDatasetRestrictions: function(){
var self = this;
$.post( ( window.galaxy_config ? galaxy_config.root : '/' ) + "api/libraries/datasets/" + self.id + "/permissions?action=remove_restrictions")
$.post( Galaxy.root + "api/libraries/datasets/" + self.id + "/permissions?action=remove_restrictions")
.done(function(fetched_permissions) {
self.model.set({is_unrestricted:true});
self.showPermissions({fetched_permissions:fetched_permissions})
@@ -230,7 +230,7 @@ var LibraryView = Backbone.View.extend({
var manage_ids = this._extractIds(this.manageSelectObject.$el.select2('data'));
var modify_ids = this._extractIds(this.modifySelectObject.$el.select2('data'));
$.post( ( window.galaxy_config ? galaxy_config.root : '/' ) + "api/libraries/" + self.id + "/permissions?action=set_permissions", { 'access_ids[]': access_ids, 'add_ids[]': add_ids, 'manage_ids[]': manage_ids, 'modify_ids[]': modify_ids, } )
$.post( Galaxy.root + "api/libraries/" + self.id + "/permissions?action=set_permissions", { 'access_ids[]': access_ids, 'add_ids[]': add_ids, 'manage_ids[]': manage_ids, 'modify_ids[]': modify_ids, } )
.done(function(fetched_permissions){
//fetch dataset again
self.showPermissions({fetched_permissions:fetched_permissions})
@@ -287,7 +287,7 @@ var LibraryView = Backbone.View.extend({
var tmpl_array = [];
// CONTAINER START
tmpl_array.push('<div class="library_style_container">');
tmpl_array.push(' <div id="library_toolbar">');
tmpl_array.push(' <a href="#"><button data-toggle="tooltip" data-placement="top" title="Go back to the list of Libraries" class="btn btn-default primary-button" type="button"><span class="fa fa-list"></span> Libraries</span></button></a>');
@@ -302,7 +302,7 @@ var LibraryView = Backbone.View.extend({
tmpl_array.push('You can assign any number of roles to any of the following permission types. However please read carefully the implications of such actions.');
tmpl_array.push('<% }%>');
tmpl_array.push('</div>');
tmpl_array.push('<div class="dataset_table">');
tmpl_array.push('<h2>Library permissions</h2>');
@@ -310,7 +310,7 @@ var LibraryView = Backbone.View.extend({
tmpl_array.push('<h4>Roles that can access the library</h4>');
tmpl_array.push('<div id="access_perm" class="access_perm roles-selection"></div>');
tmpl_array.push('<div class="alert alert-info roles-selection">User with <strong>any</strong> of these roles can access this library. If there are no access roles set on the library it is considered <strong>unrestricted</strong>.</div>');
tmpl_array.push('<h4>Roles that can manage permissions on this library</h4>');
tmpl_array.push('<div id="manage_perm" class="manage_perm roles-selection"></div>');
tmpl_array.push('<div class="alert alert-info roles-selection">User with <strong>any</strong> of these roles can manage permissions on this library (includes giving access).</div>');
@@ -1,5 +1,5 @@
define([
"galaxy.masthead",
"layout/masthead",
"mvc/base-mvc",
"utils/utils",
"libs/toastr",
@@ -29,7 +29,7 @@ var LibraryListView = Backbone.View.extend({
},
/**
* Initialize and fetch the libraries from server.
* Initialize and fetch the libraries from server.
* Async render afterwards.
* @param {object} options an object with options
*/
@@ -53,10 +53,10 @@ var LibraryListView = Backbone.View.extend({
});
},
/**
* Render the libraries table either from the object's own collection,
/**
* Render the libraries table either from the object's own collection,
* or from a given array of library models,
* or render an empty list in case no data is given.
* or render an empty list in case no data is given.
*/
render: function ( options ) {
this.options = _.extend( this.options, options );
@@ -119,7 +119,7 @@ var LibraryListView = Backbone.View.extend({
$( "#center" ).css( 'overflow','auto' );
},
/**
/**
* Render all given models as rows in the library list
* @param {array} libraries_to_render array of library models to render
*/
@@ -155,7 +155,7 @@ var LibraryListView = Backbone.View.extend({
/**
* Sort the underlying collection according to the parameters received.
* Currently supports only sorting by name.
* Currently supports only sorting by name.
*/
sortLibraries: function(){
if (Galaxy.libraries.preferences.get('sort_by') === 'name'){
@@ -1,6 +1,6 @@
// dependencies
define([
"galaxy.masthead",
"layout/masthead",
"utils/utils",
"libs/toastr"],
function(mod_masthead,
@@ -18,7 +18,7 @@ var LibraryRowView = Backbone.View.extend({
},
edit_mode: false,
element_visibility_config: {
upload_library_btn: false,
edit_library_btn: false,
@@ -45,22 +45,22 @@ var LibraryRowView = Backbone.View.extend({
},
repaint: function(library){
/* need to hide manually because of the element removal in setElement
/* need to hide manually because of the element removal in setElement
invoked in render() */
$(".tooltip").hide();
/* we need to store the old element to be able to replace it with
/* we need to store the old element to be able to replace it with
new one */
var old_element = this.$el;
/* if user canceled the library param is undefined,
/* if user canceled the library param is undefined,
if user saved and succeeded the updated library is rendered */
this.render(library);
this.render();
old_element.replaceWith(this.$el);
/* now we attach new tooltips to the newly created row element */
this.$el.find("[data-toggle]").tooltip();
},
/**
* Function modifies the visibility of buttons for
* Function modifies the visibility of buttons for
* the filling of the row template of given library.
*/
prepareButtons: function(library){
@@ -223,57 +223,52 @@ var LibraryRowView = Backbone.View.extend({
},
templateRow: function() {
tmpl_array = [];
tmpl_array.push(' <tr class="<% if(library.get("deleted") === true) { print("active") } %>" style="display:none;" data-id="<%- library.get("id") %>">');
tmpl_array.push(' <% if(!edit_mode) { %>');
tmpl_array.push(' <% if(library.get("deleted")) { %>');
tmpl_array.push(' <td style="color:grey;"><span data-toggle="tooltip" data-placement="top" title="Marked deleted" style="color:grey;" class="fa fa-ban fa-lg deleted_lib_ico"> </span> <%- library.get("name") %></td>');
tmpl_array.push(' <% } else { %>');
tmpl_array.push(' <td><a href="#folders/<%- library.get("root_folder_id") %>"><%- library.get("name") %></a></td>');
tmpl_array.push(' <% } %>');
tmpl_array.push(' <% if(library.get("description")) { %>');
tmpl_array.push(' <% if( (library.get("description")).length> 80 ) { %>');
tmpl_array.push(' <td data-toggle="tooltip" data-placement="bottom" title="<%= _.escape(library.get("description")) %>"><%= _.escape(library.get("description")).substring(0, 80) + "..." %></td>');
tmpl_array.push(' <% } else { %>');
tmpl_array.push(' <td><%= _.escape(library.get("description"))%></td>');
tmpl_array.push(' <% } %>');
tmpl_array.push(' <% } else { %>');
tmpl_array.push(' <td></td>');
tmpl_array.push(' <% } %>');
tmpl_array.push(' <% if(library.get("synopsis")) { %>');
tmpl_array.push(' <% if( (library.get("synopsis")).length> 120 ) { %>');
tmpl_array.push(' <td data-toggle="tooltip" data-placement="bottom" title="<%= _.escape(library.get("synopsis")) %>"><%= _.escape(library.get("synopsis")).substring(0, 120) + "..." %></td>');
tmpl_array.push(' <% } else { %>');
tmpl_array.push(' <td><%= _.escape(library.get("synopsis"))%></td>');
tmpl_array.push(' <% } %>');
tmpl_array.push(' <% } else { %>');
tmpl_array.push(' <td></td>');
tmpl_array.push(' <% } %>');
tmpl_array.push(' <% } else if(edit_mode){ %>');
tmpl_array.push(' <td><textarea rows="4" class="form-control input_library_name" placeholder="name" ><%- library.get("name") %></textarea></td>');
tmpl_array.push(' <td><textarea rows="4" class="form-control input_library_description" placeholder="description" ><%- library.get("description") %></textarea></td>');
tmpl_array.push(' <td><textarea rows="4" class="form-control input_library_synopsis" placeholder="synopsis" ><%- library.get("synopsis") %></textarea></td>');
tmpl_array.push(' <% } %>');
tmpl_array.push(' <td class="right-center">');
tmpl_array.push(' <% if( (library.get("public")) && (library.get("deleted") === false) ) { %>');
tmpl_array.push(' <span data-toggle="tooltip" data-placement="top" title="Unrestricted library" style="color:grey;" class="fa fa-globe fa-lg public_lib_ico"> </span>');
tmpl_array.push(' <% }%>');
tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Modify <%- library.get("name") %>" class="primary-button btn-xs edit_library_btn" type="button" style="<% if(button_config.edit_library_btn === false) { print("display:none;") } %>"><span class="fa fa-pencil"></span></button>');
tmpl_array.push(' <a href="#library/<%- library.get("id") %>/permissions"> <button data-toggle="tooltip" data-placement="top" title="Modify permissions" class="primary-button btn-xs permission_library_btn" type="button" style="<% if(button_config.permission_library_btn === false) { print("display:none;") } %>"><span class="fa fa-group"></span></button></a>');
tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Save changes" class="primary-button btn-xs save_library_btn" type="button" style="<% if(button_config.save_library_btn === false) { print("display:none;") } %>"><span class="fa fa-floppy-o"> Save</span></button>');
tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Discard changes" class="primary-button btn-xs cancel_library_btn" type="button" style="<% if(button_config.cancel_library_btn === false) { print("display:none;") } %>"><span class="fa fa-times"> Cancel</span></button>');
tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Delete <%- library.get("name") %>" class="primary-button btn-xs delete_library_btn" type="button" style="<% if(button_config.delete_library_btn === false) { print("display:none;") } %>"><span class="fa fa-trash-o"> Delete</span></button>');
tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Undelete <%- library.get("name") %> " class="primary-button btn-xs undelete_library_btn" type="button" style="<% if(button_config.undelete_library_btn === false) { print("display:none;") } %>"><span class="fa fa-unlock"> Undelete</span></button>');
tmpl_array.push(' </td>');
tmpl_array.push(' </tr>');
return _.template(tmpl_array.join(''));
return _.template([
'<tr class="<% if(library.get("deleted") === true) { print("active") } %>" style="display:none;" data-id="<%- library.get("id") %>">',
'<% if(!edit_mode) { %>',
'<% if(library.get("deleted")) { %>',
'<td style="color:grey;"><span data-toggle="tooltip" data-placement="top" title="Marked deleted" style="color:grey;" class="fa fa-ban fa-lg deleted_lib_ico"> </span> <%- library.get("name") %></td>',
'<% } else { %>',
'<td><a href="#folders/<%- library.get("root_folder_id") %>"><%- library.get("name") %></a></td>',
'<% } %>',
'<% if(library.get("description")) { %>',
'<% if( (library.get("description")).length> 80 ) { %>',
'<td data-toggle="tooltip" data-placement="bottom" title="<%= _.escape(library.get("description")) %>"><%= _.escape(library.get("description")).substring(0, 80) + "..." %></td>',
'<% } else { %>',
'<td><%= _.escape(library.get("description"))%></td>',
'<% } %>',
'<% } else { %>',
'<td></td>',
'<% } %>',
'<% if(library.get("synopsis")) { %>',
'<% if( (library.get("synopsis")).length> 120 ) { %>',
'<td data-toggle="tooltip" data-placement="bottom" title="<%= _.escape(library.get("synopsis")) %>"><%= _.escape(library.get("synopsis")).substring(0, 120) + "..." %></td>',
'<% } else { %>',
'<td><%= _.escape(library.get("synopsis"))%></td>',
'<% } %>',
'<% } else { %>',
'<td></td>',
'<% } %>',
'<% } else if(edit_mode){ %>',
'<td><textarea rows="4" class="form-control input_library_name" placeholder="name" ><%- library.get("name") %></textarea></td>',
'<td><textarea rows="4" class="form-control input_library_description" placeholder="description" ><%- library.get("description") %></textarea></td>',
'<td><textarea rows="4" class="form-control input_library_synopsis" placeholder="synopsis" ><%- library.get("synopsis") %></textarea></td>',
'<% } %>',
'<td class="right-center">',
'<% if( (library.get("public")) && (library.get("deleted") === false) ) { %>',
'<span data-toggle="tooltip" data-placement="top" title="Unrestricted library" style="color:grey;" class="fa fa-globe fa-lg public_lib_ico"> </span>',
'<% }%>',
'<button data-toggle="tooltip" data-placement="top" title="Modify \'<%- library.get("name") %>\'" class="primary-button btn-xs edit_library_btn" type="button" style="<% if(button_config.edit_library_btn === false) { print("display:none;") } %>"><span class="fa fa-pencil"></span></button>',
'<a href="#library/<%- library.get("id") %>/permissions"><button data-toggle="tooltip" data-placement="top" title="Manage \'<%- library.get("name") %>\'" class="primary-button btn-xs permission_library_btn" type="button" style="<% if(button_config.permission_library_btn === false) { print("display:none;") } %>"><span class="fa fa-group"></span></button></a>',
'<button data-toggle="tooltip" data-placement="top" title="Save changes" class="primary-button btn-xs save_library_btn" type="button" style="<% if(button_config.save_library_btn === false) { print("display:none;") } %>"><span class="fa fa-floppy-o"> Save</span></button>',
'<button data-toggle="tooltip" data-placement="top" title="Discard changes" class="primary-button btn-xs cancel_library_btn" type="button" style="<% if(button_config.cancel_library_btn === false) { print("display:none;") } %>"><span class="fa fa-times"> Cancel</span></button>',
'<button data-toggle="tooltip" data-placement="top" title="Delete <%- library.get("name") %>" class="primary-button btn-xs delete_library_btn" type="button" style="<% if(button_config.delete_library_btn === false) { print("display:none;") } %>"><span class="fa fa-trash-o"> Delete</span></button>',
'<button data-toggle="tooltip" data-placement="top" title="Undelete <%- library.get("name") %> " class="primary-button btn-xs undelete_library_btn" type="button" style="<% if(button_config.undelete_library_btn === false) { print("display:none;") } %>"><span class="fa fa-unlock"> Undelete</span></button>',
'</td>',
'</tr>'
].join(''));
}
});
return {

Some files were not shown because too many files have changed in this diff Show More