mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-21 13:50:20 +08:00
Merge remote-tracking branch 'jmchilton/dev' into csv_fix
This commit is contained in:
@@ -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 ]"
|
||||
@@ -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 ]"
|
||||
@@ -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
|
||||
@@ -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/
|
||||
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
flake8 --exclude `paste -sd, .ci/flake8_blacklist.txt` `paste -s .ci/py3_sources.txt`
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
cd /data/client && \
|
||||
npm install && \
|
||||
grunt
|
||||
@@ -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
@@ -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
@@ -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
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
@@ -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%;"/>' );
|
||||
});
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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
|
||||
};
|
||||
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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
|
||||
@@ -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){
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
});
|
||||
@@ -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
|
||||
};
|
||||
|
||||
});
|
||||
@@ -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);
|
||||
//}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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: " ", 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 );
|
||||
@@ -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
|
||||
};
|
||||
|
||||
});
|
||||
@@ -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
|
||||
};
|
||||
|
||||
});
|
||||
@@ -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
|
||||
};
|
||||
|
||||
});
|
||||
@@ -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: " ",
|
||||
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,
|
||||
};
|
||||
});
|
||||
@@ -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
|
||||
};
|
||||
});
|
||||
@@ -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
|
||||
};
|
||||
});
|
||||
@@ -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
@@ -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
@@ -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">« Prev</button> <button class="btn btn-sm btn-default" data-role="next">Next »</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);
|
||||
@@ -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 = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
'`': '`'
|
||||
};
|
||||
|
||||
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' ) );
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
@@ -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>';
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -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( {},
|
||||
|
||||
+30
-27
@@ -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
|
||||
};
|
||||
});
|
||||
+33
-29
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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' );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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>';
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
|
||||
|
||||
@@ -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,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' ) );
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
|
||||
+11
-8
@@ -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
|
||||
};
|
||||
});
|
||||
+44
-46
@@ -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
|
||||
};
|
||||
});
|
||||
+33
-29
@@ -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
|
||||
};
|
||||
});
|
||||
+21
-18
@@ -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 );
|
||||
};
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user