mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Very preliminary start on the workflow editor. Currently:
- Can add steps (tool invocations) to the workflow - Can modify options for tools that do not use dynamic options or nesting - Can connect outputs to inputs, the editor does check type compatibility (however this breaks down completely for the "input" type) There is no way to save or run workflows yet (and not data model for them). You'll need to set "enable_beta_features = True" in your config for this to be accessible.
This commit is contained in:
@@ -22,6 +22,7 @@ class Configuration( object ):
|
||||
def __init__( self, **kwargs ):
|
||||
self.config_dict = kwargs
|
||||
self.root = kwargs.get( 'root_dir', '.' )
|
||||
self.enable_beta_features = kwargs.get( "enable_beta_features", False )
|
||||
self.database = resolve_path( kwargs.get( "database_file", "database/universe.d" ), self.root )
|
||||
self.database_connection = kwargs.get( "database_connection", False )
|
||||
self.file_path = resolve_path( kwargs.get( "file_path", "database/files" ), self.root )
|
||||
|
||||
@@ -15,6 +15,8 @@ class BaseController( object ):
|
||||
"""
|
||||
Base class for Galaxy web application controllers.
|
||||
"""
|
||||
|
||||
beta = False
|
||||
|
||||
def __init__( self, app ):
|
||||
"""Initialize an interface for application 'app'"""
|
||||
|
||||
@@ -41,7 +41,8 @@ def add_controllers( webapp, app ):
|
||||
for key in dir( module ):
|
||||
T = getattr( module, key )
|
||||
if isclass( T ) and T is not BaseController and issubclass( T, BaseController ):
|
||||
webapp.add_controller( name, T( app ) )
|
||||
if app.config.enable_beta_features or not ( T.beta ):
|
||||
webapp.add_controller( name, T( app ) )
|
||||
|
||||
def app_factory( global_conf, **kwargs ):
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
from galaxy.web.base.controller import *
|
||||
|
||||
from galaxy.tools.parameters import DataToolParameter
|
||||
from galaxy.datatypes.data import Data
|
||||
|
||||
class WorkflowEditor( BaseController ):
|
||||
beta = True
|
||||
|
||||
@web.expose
|
||||
def index( self, trans ):
|
||||
return trans.fill_template( "workflow_editor/index.mako" )
|
||||
|
||||
@web.expose
|
||||
def canvas( self, trans ):
|
||||
return trans.fill_template( "workflow_editor/canvas.mako" )
|
||||
|
||||
@web.expose
|
||||
def tool_form( self, trans, tool_id ):
|
||||
tool = trans.app.toolbox.tools_by_id[tool_id]
|
||||
return trans.fill_template( "workflow_editor/tool_form.mako", tool=tool, as_html=as_html )
|
||||
|
||||
@web.json
|
||||
def get_tool_info( self, trans, tool_id ):
|
||||
tool = trans.app.toolbox.tools_by_id[tool_id]
|
||||
rval = {}
|
||||
rval['name'] = tool.name
|
||||
data_inputs = []
|
||||
for name, input in tool.inputs.iteritems():
|
||||
d = dict( data=False, name=input.name, label=input.label, html=as_html( input, None ) )
|
||||
if isinstance( input, DataToolParameter ):
|
||||
d.update( dict( data=True, extensions=input.extensions ) )
|
||||
data_inputs.append( d )
|
||||
rval['data_inputs'] = data_inputs
|
||||
data_outputs = []
|
||||
for name, ( format, metadata_source, parent ) in tool.outputs.iteritems():
|
||||
data_outputs.append( dict( name=name, extension=format ) )
|
||||
rval['data_outputs'] = data_outputs
|
||||
return rval
|
||||
|
||||
@web.json
|
||||
def get_datatypes( self, trans ):
|
||||
ext_to_class_name = dict()
|
||||
classes = []
|
||||
for k, v in trans.app.datatypes_registry.datatypes_by_extension.iteritems():
|
||||
c = v.__class__
|
||||
ext_to_class_name[k] = c.__module__ + "." + c.__name__
|
||||
classes.append( c )
|
||||
class_to_classes = dict()
|
||||
def visit_bases( types, cls ):
|
||||
for base in cls.__bases__:
|
||||
if issubclass( base, Data ):
|
||||
types.add( base.__module__ + "." + base.__name__ )
|
||||
visit_bases( types, base )
|
||||
for c in classes:
|
||||
n = c.__module__ + "." + c.__name__
|
||||
types = set( [ n ] )
|
||||
visit_bases( types, c )
|
||||
class_to_classes[ n ] = dict( ( t, True ) for t in types )
|
||||
return dict( ext_to_class_name=ext_to_class_name, class_to_classes=class_to_classes )
|
||||
|
||||
def as_html( param, trans ):
|
||||
if type( param ) is DataToolParameter:
|
||||
return "Data input '" + param.name + "' (" + ( " or ".join( param.extensions ) ) + ")"
|
||||
else:
|
||||
return param.get_html( trans )
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* jQuery blockUI plugin
|
||||
* Version 1.33 (09/14/2007)
|
||||
* @requires jQuery v1.1.1
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Examples at: http://malsup.com/jquery/block/
|
||||
* Copyright (c) 2007 M. Alsup
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
(function($) {
|
||||
/**
|
||||
* blockUI provides a mechanism for blocking user interaction with a page (or parts of a page).
|
||||
* This can be an effective way to simulate synchronous behavior during ajax operations without
|
||||
* locking the browser. It will prevent user operations for the current page while it is
|
||||
* active ane will return the page to normal when it is deactivate. blockUI accepts the following
|
||||
* two optional arguments:
|
||||
*
|
||||
* message (String|Element|jQuery): The message to be displayed while the UI is blocked. The message
|
||||
* argument can be a plain text string like "Processing...", an HTML string like
|
||||
* "<h1><img src="busy.gif" /> Please wait...</h1>", a DOM element, or a jQuery object.
|
||||
* The default message is "<h1>Please wait...</h1>"
|
||||
*
|
||||
* css (Object): Object which contains css property/values to override the default styles of
|
||||
* the message. Use this argument if you wish to override the default
|
||||
* styles. The css Object should be in a format suitable for the jQuery.css
|
||||
* function. For example:
|
||||
* $.blockUI({
|
||||
* backgroundColor: '#ff8',
|
||||
* border: '5px solid #f00,
|
||||
* fontWeight: 'bold'
|
||||
* });
|
||||
*
|
||||
* The default blocking message used when blocking the entire page is "<h1>Please wait...</h1>"
|
||||
* but this can be overridden by assigning a value to $.blockUI.defaults.pageMessage in your
|
||||
* own code. For example:
|
||||
*
|
||||
* $.blockUI.defaults.pageMessage = "<h1>Bitte Wartezeit</h1>";
|
||||
*
|
||||
* The default message styling can also be overridden. For example:
|
||||
*
|
||||
* $.extend($.blockUI.defaults.pageMessageCSS, { color: '#00a', backgroundColor: '#0f0' });
|
||||
*
|
||||
* The default styles work well for simple messages like "Please wait", but for longer messages
|
||||
* style overrides may be necessary.
|
||||
*
|
||||
* @example $.blockUI();
|
||||
* @desc prevent user interaction with the page (and show the default message of 'Please wait...')
|
||||
*
|
||||
* @example $.blockUI( { backgroundColor: '#f00', color: '#fff'} );
|
||||
* @desc prevent user interaction and override the default styles of the message to use a white on red color scheme
|
||||
*
|
||||
* @example $.blockUI('Processing...');
|
||||
* @desc prevent user interaction and display the message "Processing..." instead of the default message
|
||||
*
|
||||
* @name blockUI
|
||||
* @param String|jQuery|Element message Message to display while the UI is blocked
|
||||
* @param Object css Style object to control look of the message
|
||||
* @cat Plugins/blockUI
|
||||
*/
|
||||
$.blockUI = function(msg, css, opts) {
|
||||
$.blockUI.impl.install(window, msg, css, opts);
|
||||
};
|
||||
|
||||
// expose version number so other plugins can interogate
|
||||
$.blockUI.version = 1.33;
|
||||
|
||||
/**
|
||||
* unblockUI removes the UI block that was put in place by blockUI
|
||||
*
|
||||
* @example $.unblockUI();
|
||||
* @desc unblocks the page
|
||||
*
|
||||
* @name unblockUI
|
||||
* @cat Plugins/blockUI
|
||||
*/
|
||||
$.unblockUI = function(opts) {
|
||||
$.blockUI.impl.remove(window, opts);
|
||||
};
|
||||
|
||||
/**
|
||||
* Blocks user interaction with the selected elements. (Hat tip: Much of
|
||||
* this logic comes from Brandon Aaron's bgiframe plugin. Thanks, Brandon!)
|
||||
* By default, no message is displayed when blocking elements.
|
||||
*
|
||||
* @example $('div.special').block();
|
||||
* @desc prevent user interaction with all div elements with the 'special' class.
|
||||
*
|
||||
* @example $('div.special').block('Please wait');
|
||||
* @desc prevent user interaction with all div elements with the 'special' class
|
||||
* and show a message over the blocked content.
|
||||
*
|
||||
* @name block
|
||||
* @type jQuery
|
||||
* @param String|jQuery|Element message Message to display while the element is blocked
|
||||
* @param Object css Style object to control look of the message
|
||||
* @cat Plugins/blockUI
|
||||
*/
|
||||
$.fn.block = function(msg, css, opts) {
|
||||
return this.each(function() {
|
||||
if (!this.$pos_checked) {
|
||||
if ($.css(this,"position") == 'static')
|
||||
this.style.position = 'relative';
|
||||
if ($.browser.msie) this.style.zoom = 1; // force 'hasLayout' in IE
|
||||
this.$pos_checked = 1;
|
||||
}
|
||||
$.blockUI.impl.install(this, msg, css, opts);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Unblocks content that was blocked by "block()"
|
||||
*
|
||||
* @example $('div.special').unblock();
|
||||
* @desc unblocks all div elements with the 'special' class.
|
||||
*
|
||||
* @name unblock
|
||||
* @type jQuery
|
||||
* @cat Plugins/blockUI
|
||||
*/
|
||||
$.fn.unblock = function(opts) {
|
||||
return this.each(function() {
|
||||
$.blockUI.impl.remove(this, opts);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* displays the first matched element in a "display box" above a page overlay.
|
||||
*
|
||||
* @example $('#myImage').displayBox();
|
||||
* @desc displays "myImage" element in a box
|
||||
*
|
||||
* @name displayBox
|
||||
* @type jQuery
|
||||
* @cat Plugins/blockUI
|
||||
*/
|
||||
$.fn.displayBox = function(css, fn, isFlash) {
|
||||
var msg = this[0];
|
||||
if (!msg) return;
|
||||
var $msg = $(msg);
|
||||
css = css || {};
|
||||
|
||||
var w = $msg.width() || $msg.attr('width') || css.width || $.blockUI.defaults.displayBoxCSS.width;
|
||||
var h = $msg.height() || $msg.attr('height') || css.height || $.blockUI.defaults.displayBoxCSS.height ;
|
||||
if (w[w.length-1] == '%') {
|
||||
var ww = document.documentElement.clientWidth || document.body.clientWidth;
|
||||
w = parseInt(w) || 100;
|
||||
w = (w * ww) / 100;
|
||||
}
|
||||
if (h[h.length-1] == '%') {
|
||||
var hh = document.documentElement.clientHeight || document.body.clientHeight;
|
||||
h = parseInt(h) || 100;
|
||||
h = (h * hh) / 100;
|
||||
}
|
||||
|
||||
var ml = '-' + parseInt(w)/2 + 'px';
|
||||
var mt = '-' + parseInt(h)/2 + 'px';
|
||||
|
||||
// supress opacity on overlay if displaying flash content on mac/ff platform
|
||||
var ua = navigator.userAgent.toLowerCase();
|
||||
var opts = {
|
||||
displayMode: fn || 1,
|
||||
noalpha: isFlash && /mac/.test(ua) && /firefox/.test(ua)
|
||||
};
|
||||
|
||||
$.blockUI.impl.install(window, msg, { width: w, height: h, marginTop: mt, marginLeft: ml }, opts);
|
||||
};
|
||||
|
||||
|
||||
// override these in your code to change the default messages and styles
|
||||
$.blockUI.defaults = {
|
||||
// the message displayed when blocking the entire page
|
||||
pageMessage: '<h1>Please wait...</h1>',
|
||||
// the message displayed when blocking an element
|
||||
elementMessage: '', // none
|
||||
// styles for the overlay iframe
|
||||
overlayCSS: { backgroundColor: '#fff', opacity: '0.5' },
|
||||
// styles for the message when blocking the entire page
|
||||
pageMessageCSS: { width:'250px', margin:'-50px 0 0 -125px', top:'50%', left:'50%', textAlign:'center', color:'#000', backgroundColor:'#fff', border:'3px solid #aaa' },
|
||||
// styles for the message when blocking an element
|
||||
elementMessageCSS: { width:'250px', padding:'10px', textAlign:'center', backgroundColor:'#fff'},
|
||||
// styles for the displayBox
|
||||
displayBoxCSS: { width: '400px', height: '400px', top:'50%', left:'50%' },
|
||||
// allow body element to be stetched in ie6
|
||||
ie6Stretch: 1,
|
||||
// supress tab nav from leaving blocking content?
|
||||
allowTabToLeave: 0,
|
||||
// Title attribute for overlay when using displayBox
|
||||
closeMessage: 'Click to close',
|
||||
// use fadeOut effect when unblocking (can be overridden on unblock call)
|
||||
fadeOut: 1,
|
||||
// fadeOut transition time in millis
|
||||
fadeTime: 400
|
||||
};
|
||||
|
||||
// the gory details
|
||||
$.blockUI.impl = {
|
||||
box: null,
|
||||
boxCallback: null,
|
||||
pageBlock: null,
|
||||
pageBlockEls: [],
|
||||
op8: window.opera && window.opera.version() < 9,
|
||||
ie6: $.browser.msie && /MSIE 6.0/.test(navigator.userAgent),
|
||||
install: function(el, msg, css, opts) {
|
||||
opts = opts || {};
|
||||
this.boxCallback = typeof opts.displayMode == 'function' ? opts.displayMode : null;
|
||||
this.box = opts.displayMode ? msg : null;
|
||||
var full = (el == window);
|
||||
|
||||
// use logical settings for opacity support based on browser but allow overrides via opts arg
|
||||
var noalpha = this.op8 || $.browser.mozilla && /Linux/.test(navigator.platform);
|
||||
if (typeof opts.alphaOverride != 'undefined')
|
||||
noalpha = opts.alphaOverride == 0 ? 1 : 0;
|
||||
|
||||
if (full && this.pageBlock) this.remove(window, {fadeOut:0});
|
||||
// check to see if we were only passed the css object (a literal)
|
||||
if (msg && typeof msg == 'object' && !msg.jquery && !msg.nodeType) {
|
||||
css = msg;
|
||||
msg = null;
|
||||
}
|
||||
msg = msg ? (msg.nodeType ? $(msg) : msg) : full ? $.blockUI.defaults.pageMessage : $.blockUI.defaults.elementMessage;
|
||||
if (opts.displayMode)
|
||||
var basecss = jQuery.extend({}, $.blockUI.defaults.displayBoxCSS);
|
||||
else
|
||||
var basecss = jQuery.extend({}, full ? $.blockUI.defaults.pageMessageCSS : $.blockUI.defaults.elementMessageCSS);
|
||||
css = jQuery.extend(basecss, css || {});
|
||||
var f = ($.browser.msie) ? $('<iframe class="blockUI" style="z-index:1000;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="javascript:false;"></iframe>')
|
||||
: $('<div class="blockUI" style="display:none"></div>');
|
||||
var w = $('<div class="blockUI" style="z-index:1001;cursor:wait;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
|
||||
var m = full ? $('<div class="blockUI blockMsg" style="z-index:1002;cursor:wait;padding:0;position:fixed"></div>')
|
||||
: $('<div class="blockUI" style="display:none;z-index:1002;cursor:wait;position:absolute"></div>');
|
||||
w.css('position', full ? 'fixed' : 'absolute');
|
||||
if (msg) m.css(css);
|
||||
if (!noalpha) w.css($.blockUI.defaults.overlayCSS);
|
||||
if (this.op8) w.css({ width:''+el.clientWidth,height:''+el.clientHeight }); // lame
|
||||
if ($.browser.msie) f.css('opacity','0.0');
|
||||
|
||||
$([f[0],w[0],m[0]]).appendTo(full ? 'body' : el);
|
||||
|
||||
// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
|
||||
var expr = $.browser.msie && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
|
||||
if (this.ie6 || expr) {
|
||||
// stretch content area if it's short
|
||||
if (full && $.blockUI.defaults.ie6Stretch && $.boxModel)
|
||||
$('html,body').css('height','100%');
|
||||
|
||||
// fix ie6 problem when blocked element has a border width
|
||||
if ((this.ie6 || !$.boxModel) && !full) {
|
||||
var t = this.sz(el,'borderTopWidth'), l = this.sz(el,'borderLeftWidth');
|
||||
var fixT = t ? '(0 - '+t+')' : 0;
|
||||
var fixL = l ? '(0 - '+l+')' : 0;
|
||||
}
|
||||
|
||||
// simulate fixed position
|
||||
$.each([f,w,m], function(i,o) {
|
||||
var s = o[0].style;
|
||||
s.position = 'absolute';
|
||||
if (i < 2) {
|
||||
full ? s.setExpression('height','document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + "px"')
|
||||
: s.setExpression('height','this.parentNode.offsetHeight + "px"');
|
||||
full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
|
||||
: s.setExpression('width','this.parentNode.offsetWidth + "px"');
|
||||
if (fixL) s.setExpression('left', fixL);
|
||||
if (fixT) s.setExpression('top', fixT);
|
||||
}
|
||||
else {
|
||||
if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
|
||||
s.marginTop = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (opts.displayMode) {
|
||||
w.css('cursor','default').attr('title', $.blockUI.defaults.closeMessage);
|
||||
m.css('cursor','default');
|
||||
$([f[0],w[0],m[0]]).removeClass('blockUI').addClass('displayBox');
|
||||
$().click($.blockUI.impl.boxHandler).bind('keypress', $.blockUI.impl.boxHandler);
|
||||
}
|
||||
else
|
||||
this.bind(1, el);
|
||||
m.append(msg).show();
|
||||
if (msg.jquery) msg.show();
|
||||
if (opts.displayMode) return;
|
||||
if (full) {
|
||||
this.pageBlock = m[0];
|
||||
this.pageBlockEls = $(':input:enabled:visible',this.pageBlock);
|
||||
setTimeout(this.focus, 20);
|
||||
}
|
||||
else this.center(m[0]);
|
||||
},
|
||||
remove: function(el, opts) {
|
||||
var o = $.extend({}, $.blockUI.defaults, opts);
|
||||
this.bind(0, el);
|
||||
var full = el == window;
|
||||
var els = full ? $('body').children().filter('.blockUI') : $('.blockUI', el);
|
||||
if (full) this.pageBlock = this.pageBlockEls = null;
|
||||
|
||||
if (o.fadeOut) {
|
||||
els.fadeOut(o.fadeTime, function() {
|
||||
if (this.parentNode) this.parentNode.removeChild(this);
|
||||
});
|
||||
}
|
||||
else els.remove();
|
||||
},
|
||||
boxRemove: function(el) {
|
||||
$().unbind('click',$.blockUI.impl.boxHandler).unbind('keypress', $.blockUI.impl.boxHandler);
|
||||
if (this.boxCallback)
|
||||
this.boxCallback(this.box);
|
||||
$('body .displayBox').hide().remove();
|
||||
},
|
||||
// event handler to suppress keyboard/mouse events when blocking
|
||||
handler: function(e) {
|
||||
if (e.keyCode && e.keyCode == 9) {
|
||||
if ($.blockUI.impl.pageBlock && !$.blockUI.defaults.allowTabToLeave) {
|
||||
var els = $.blockUI.impl.pageBlockEls;
|
||||
var fwd = !e.shiftKey && e.target == els[els.length-1];
|
||||
var back = e.shiftKey && e.target == els[0];
|
||||
if (fwd || back) {
|
||||
setTimeout(function(){$.blockUI.impl.focus(back)},10);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($(e.target).parents('div.blockMsg').length > 0)
|
||||
return true;
|
||||
return $(e.target).parents().children().filter('div.blockUI').length == 0;
|
||||
},
|
||||
boxHandler: function(e) {
|
||||
if ((e.keyCode && e.keyCode == 27) || (e.type == 'click' && $(e.target).parents('div.blockMsg').length == 0))
|
||||
$.blockUI.impl.boxRemove();
|
||||
return true;
|
||||
},
|
||||
// bind/unbind the handler
|
||||
bind: function(b, el) {
|
||||
var full = el == window;
|
||||
// don't bother unbinding if there is nothing to unbind
|
||||
if (!b && (full && !this.pageBlock || !full && !el.$blocked)) return;
|
||||
if (!full) el.$blocked = b;
|
||||
var $e = $(el).find('a,:input');
|
||||
$.each(['mousedown','mouseup','keydown','keypress','click'], function(i,o) {
|
||||
$e[b?'bind':'unbind'](o, $.blockUI.impl.handler);
|
||||
});
|
||||
},
|
||||
focus: function(back) {
|
||||
if (!$.blockUI.impl.pageBlockEls) return;
|
||||
var e = $.blockUI.impl.pageBlockEls[back===true ? $.blockUI.impl.pageBlockEls.length-1 : 0];
|
||||
if (e) e.focus();
|
||||
},
|
||||
center: function(el) {
|
||||
var p = el.parentNode, s = el.style;
|
||||
var l = ((p.offsetWidth - el.offsetWidth)/2) - this.sz(p,'borderLeftWidth');
|
||||
var t = ((p.offsetHeight - el.offsetHeight)/2) - this.sz(p,'borderTopWidth');
|
||||
s.left = l > 0 ? (l+'px') : '0';
|
||||
s.top = t > 0 ? (t+'px') : '0';
|
||||
},
|
||||
sz: function(el, p) { return parseInt($.css(el,p))||0; }
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,396 @@
|
||||
<html>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
<link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" />
|
||||
|
||||
<style>
|
||||
* { z-index: 500;}
|
||||
canvas { position: absolute; z-index: 10; }
|
||||
canvas.dragging { position: absolute; z-index: 1000; }
|
||||
.node { position: absolute; width: 100px; background: green; }
|
||||
.input-terminal { width: 10px; height: 10px; background: red; position: absolute; bottom: 0; left: -17px; }
|
||||
.output-terminal { width: 10px; height: 10px; background: blue; position: absolute; bottom: 0; right: -17px; }
|
||||
.drag-terminal { position: absolute; z-index: 1500; width: 10px; height: 10px; background: yellow; }
|
||||
.input-terminal-active { background: yellow; }
|
||||
.input-terminal-hover { background: yellow; border: solid black 1px; }
|
||||
.unselectable { -moz-user-select: none; -khtml-user-select: none; user-select: none; }
|
||||
</style>
|
||||
|
||||
<script type='text/javascript' src="/static/scripts/jquery.js"> </script>
|
||||
<script type='text/javascript' src="/static/scripts/jquery.dimensions.js"> </script>
|
||||
<script type='text/javascript' src="/static/scripts/jquery.ui.js"> </script>
|
||||
<script>
|
||||
var console = window.console;
|
||||
console.log( "starting" );
|
||||
|
||||
## var old_shim_w = 10;
|
||||
## var old_shim_h = 10;
|
||||
## $.ui.plugin.add("draggable", "start", "grow", function(e,ui) {
|
||||
## old_shim_w = $("#shim").width();
|
||||
## old_shim_h = $("#shim").height();
|
||||
## });
|
||||
## $.ui.plugin.add("draggable", "drag", "grow", function(e,ui) {
|
||||
## if ( ui.draggable.rpos[1] > $("#shim").height() - 100 ) { $("#shim").css( "height", $("#shim").height() + 200 ) }
|
||||
## if ( ui.draggable.rpos[0] > $("#shim").width() - 100 ) { $("#shim").css( "width", $("#shim").width() + 200 ) }
|
||||
## });
|
||||
## $.ui.plugin.add("draggable", "stop", "grow", function(e,ui) {
|
||||
## if ( ui.draggable.rpos[1] > old_shim_h - 100 ) { $("#shim").css( "height", Math.ceil( ui.draggable.rpos[1] / 200 ) * 200 ) }
|
||||
## if ( ui.draggable.rpos[0] > old_shim_w - 100 ) { $("#shim").css( "width", Math.ceil( ui.draggable.rpos[0] / 200 ) * 200 ) }
|
||||
## old_shim_w = $("#shim").width();
|
||||
## old_shim_h = $("#shim").height();
|
||||
## });
|
||||
</script>
|
||||
|
||||
<script type='text/javascript'>
|
||||
|
||||
function OutputTerminal( element, datatype ) {
|
||||
this.element = element;
|
||||
this.connectors = [];
|
||||
this.datatype = datatype
|
||||
}
|
||||
$.extend( OutputTerminal.prototype, {
|
||||
connect: function ( connector ) {
|
||||
this.connectors.push( connector );
|
||||
},
|
||||
disconnect: function ( connector ) {
|
||||
this.connectors.splice( this.connectors.indexOf( connector ), 1 );
|
||||
},
|
||||
redraw: function () {
|
||||
$.each( this.connectors, function( _, c ) {
|
||||
c.redraw();
|
||||
})
|
||||
}
|
||||
} )
|
||||
|
||||
function InputTerminal( element, datatypes ) {
|
||||
this.element = element;
|
||||
this.connectors = [];
|
||||
this.max_connections = 1;
|
||||
this.datatypes = datatypes;
|
||||
}
|
||||
$.extend( InputTerminal.prototype, {
|
||||
connect: function ( connector ) {
|
||||
this.connectors.push( connector );
|
||||
},
|
||||
disconnect: function ( connector ) {
|
||||
this.connectors.splice( this.connectors.indexOf( connector ), 1 );
|
||||
},
|
||||
can_accept: function ( other ) {
|
||||
if ( this.connectors.length < this.max_connections ) {
|
||||
for ( t in this.datatypes ) {
|
||||
## FIXME: No idea what to do about this case
|
||||
if ( other.datatype == "input" ) { return true; }
|
||||
if ( issubtype( other.datatype, this.datatypes[t] ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
redraw: function () {
|
||||
$.each( this.connectors, function( _, c ) {
|
||||
c.redraw();
|
||||
})
|
||||
}
|
||||
} )
|
||||
|
||||
function Connector( handle1, handle2 ) {
|
||||
this.canvas = null;
|
||||
this.dragging = false;
|
||||
}
|
||||
$.extend( Connector.prototype, {
|
||||
connect: function ( t1, t2 ) {
|
||||
this.handle1 = t1;
|
||||
this.handle1.connect( this );
|
||||
this.handle2 = t2;
|
||||
this.handle2.connect( this );
|
||||
},
|
||||
destroy : function () {
|
||||
if ( this.handle1 ) {
|
||||
this.handle1.disconnect( this );
|
||||
}
|
||||
if ( this.handle2 ) {
|
||||
this.handle2.disconnect( this );
|
||||
}
|
||||
$(this.canvas).remove();
|
||||
},
|
||||
redraw : function () {
|
||||
if ( ! this.canvas ) {
|
||||
this.canvas = document.createElement( "canvas" );
|
||||
$("body").append( this.canvas );
|
||||
if ( this.dragging ) { this.canvas.style.zIndex = "300" }
|
||||
}
|
||||
// Find the position of each handle
|
||||
var o = $(this.handle1.element).offset();
|
||||
var start_x = o.left + 5;
|
||||
var start_y = o.top + 5;
|
||||
var o = $(this.handle2.element).offset();
|
||||
var end_x = o.left + 5;
|
||||
var end_y = o.top + 5;
|
||||
// Calculate canvas area
|
||||
var canvas_extra = 50;
|
||||
var canvas_min_x = Math.min( start_x, end_x );
|
||||
var canvas_max_x = Math.max( start_x, end_x );
|
||||
var canvas_min_y = Math.min( start_y, end_y );
|
||||
var canvas_max_y = Math.max( start_y, end_y );
|
||||
var cp_shift = Math.max( ( canvas_max_y - canvas_min_y ) / 2, 100 );
|
||||
var canvas_left = canvas_min_x - canvas_extra;
|
||||
var canvas_top = canvas_min_y - canvas_extra;
|
||||
var canvas_width = canvas_max_x - canvas_min_x + 2 * canvas_extra;
|
||||
var canvas_height = canvas_max_y - canvas_min_y + 2 * canvas_extra;
|
||||
// Place the canvas
|
||||
this.canvas.style.left = canvas_left + "px";
|
||||
this.canvas.style.top = canvas_top + "px";
|
||||
this.canvas.setAttribute( "width", canvas_width );
|
||||
this.canvas.setAttribute( "height", canvas_height );
|
||||
// Adjust points to be relative to the canvas
|
||||
start_x -= canvas_left;
|
||||
start_y -= canvas_top;
|
||||
end_x -= canvas_left;
|
||||
end_y -= canvas_top;
|
||||
// Draw the line
|
||||
var c = this.canvas.getContext("2d");
|
||||
c.lineCap = "round";
|
||||
c.strokeStyle = "#999";
|
||||
c.lineWidth = 7;
|
||||
c.beginPath();
|
||||
c.moveTo( start_x, start_y );
|
||||
c.bezierCurveTo( start_x + cp_shift, start_y, end_x - cp_shift, end_y, end_x, end_y );
|
||||
c.stroke();
|
||||
// Inner line
|
||||
c.strokeStyle = "#EEEEEE";
|
||||
c.lineWidth = 5;
|
||||
c.beginPath();
|
||||
c.moveTo( start_x, start_y );
|
||||
c.bezierCurveTo( start_x + cp_shift, start_y, end_x - cp_shift, end_y, end_x, end_y );
|
||||
c.stroke();
|
||||
}
|
||||
} )
|
||||
|
||||
function enable_input_terminal( element, types ) {
|
||||
$(element).each( function() {
|
||||
var terminal = this.terminal = new InputTerminal( this, types );
|
||||
$(this).droppable( {
|
||||
tolerance: 'intersect',
|
||||
accept: function( draggable ) {
|
||||
return ( draggable.terminal ) && ( terminal.can_accept( draggable.terminal ) );
|
||||
},
|
||||
activeClass: 'input-terminal-active',
|
||||
hoverClass: 'input-terminal-active',
|
||||
drop: function( e, d ) {
|
||||
var source = d.draggable.element.terminal;
|
||||
var target = d.droppable.element.terminal;
|
||||
var c = new Connector();
|
||||
c.connect( source, target );
|
||||
c.redraw();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function enable_output_terminal( element, type ) {
|
||||
$(element).each( function() {
|
||||
var terminal = this.terminal = new OutputTerminal( this, type );
|
||||
$(this).draggable( {
|
||||
scroll: true,
|
||||
// containment: 'document',
|
||||
// appendTo: "body",
|
||||
// cursorAt: { top: 5, left: 5 },
|
||||
helper: function () {
|
||||
var h = $( '<div class="drag-terminal" style="position: absolute;"></div>' ).get(0);
|
||||
h.terminal = new OutputTerminal( h );
|
||||
// // Already a connector? Destroy... no wait, don't
|
||||
// if ( this.terminal.connector ) {
|
||||
// this.terminal.connector.destroy();
|
||||
// }
|
||||
var c = new Connector();
|
||||
this.drag_temp_connector = c;
|
||||
c.dragging = true;
|
||||
c.connect( this.terminal, h.terminal );
|
||||
return h;
|
||||
},
|
||||
drag: function ( e, options ) {
|
||||
options.helper.terminal.redraw();
|
||||
},
|
||||
stop: function( e, options ) {
|
||||
this.drag_temp_connector.destroy();
|
||||
// options.helper.remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function enable_drag( element ) {
|
||||
$(element).draggable( {
|
||||
cursor: 'move',
|
||||
scroll: true,
|
||||
scrollSensitivity: 100,
|
||||
## grow: true,
|
||||
start: function() {
|
||||
//$(this).css( 'z-index', '1000' );
|
||||
},
|
||||
drag: function() {
|
||||
$(this).find( ".terminal" ).each( function() {
|
||||
this.terminal.redraw();
|
||||
})
|
||||
},
|
||||
stop: function() {
|
||||
//$(this).css( 'z-index', '100' );
|
||||
$(this).find( ".terminal" ).each( function() {
|
||||
this.terminal.redraw();
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function add_node_for_tool( id ) {
|
||||
$.getJSON( "${h.url_for( action='get_tool_info' )}", { tool_id: id }, function ( data ) {
|
||||
var f = $("<div class='toolForm' style='position: absolute;'></div>");
|
||||
var title = $("<div class='toolFormTitle unselectable'>" + data.name + "</div>" )
|
||||
f.append( title );
|
||||
f.appendTo( "body" );
|
||||
var short_width = f.width();
|
||||
console.log( ">>", short_width );
|
||||
var b = $("<div class='toolFormBody'></div>")
|
||||
b.append( $( "<div class='form-row titleRow'>Inputs:</div>" ) )
|
||||
$.each( data.data_inputs, function( i, input ) {
|
||||
if ( input.data ) {
|
||||
t = $("<div class='terminal input-terminal'></div>")
|
||||
enable_input_terminal( t, input.extensions );
|
||||
b.append( $("<div class='form-row dataRow'><label>" + input.label + "</label><div>" + input.html + "</div></div>" ).prepend( t ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
b.append( $("<div class='form-row fieldRow'><label>" + input.label + "</label><div>" + input.html + "</div></div>") );
|
||||
}
|
||||
});
|
||||
b.append( $( "<div class='form-row titleRow'>Outputs:</div>" ) )
|
||||
$.each( data.data_outputs, function( i, output ) {
|
||||
var t = $( "<div class='terminal output-terminal'></div>" );
|
||||
enable_output_terminal( t, output.extension );
|
||||
b.append( $("<div class='form-row dataRow'>" + output.name + "</div>" ).append( t ) );
|
||||
});
|
||||
f.append( b )
|
||||
// Fix width to computed width
|
||||
f.css( "width", f.width() );
|
||||
// Now add floats
|
||||
var width = null;
|
||||
var buttons = $("<div style='float: right'></div>");
|
||||
var big = true;
|
||||
buttons.append( $("<a href='#'>[+]</a>").click( function() {
|
||||
b.children().not(".dataRow").toggle();
|
||||
b.children( ".dataRow" ).children( "label" ).toggle();
|
||||
f.css( "width", big ? short_width : width );
|
||||
big = ! big;
|
||||
f.find( ".terminal" ).each( function() {
|
||||
this.terminal.redraw();
|
||||
});
|
||||
} ) );
|
||||
width = f.width();
|
||||
buttons.prependTo( title );
|
||||
width += ( buttons.width() + 5 );
|
||||
short_width += ( buttons.width() + 5 );
|
||||
f.css( "width", width );
|
||||
// Make draggable
|
||||
enable_drag( f );
|
||||
});
|
||||
}
|
||||
|
||||
var ext_to_type = null;
|
||||
var type_to_type = null;
|
||||
|
||||
function issubtype( child, parent ) {
|
||||
child = ext_to_type[child];
|
||||
parent = ext_to_type[parent];
|
||||
return ( parent in type_to_type[child] );
|
||||
}
|
||||
|
||||
$( function() {
|
||||
$.getJSON( "${h.url_for( action='get_datatypes' )}", function( data ) {
|
||||
ext_to_type = data.ext_to_class_name;
|
||||
type_to_type = data.class_to_classes;
|
||||
parent.notify();
|
||||
});
|
||||
})
|
||||
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
background: white url(${h.url_for('/static/images/light_gray_grid.gif')}) repeat;
|
||||
}
|
||||
#tool-area {
|
||||
position: absolute;
|
||||
top: 0; left: 0; bottom: 0;
|
||||
width: 300px;
|
||||
overflow: scroll;
|
||||
}
|
||||
div.toolMenu {
|
||||
margin: 5px;
|
||||
}
|
||||
div.toolSectionPad {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 5px;
|
||||
font-size: 0px;
|
||||
}
|
||||
div.toolSectionDetailsInner {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
div.toolSectionTitle {
|
||||
padding-bottom: 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
div.toolTitle {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
margin-left: 16px;
|
||||
margin-right: 10px;
|
||||
display: list-item;
|
||||
list-style: square outside;
|
||||
}
|
||||
div.titleRow {
|
||||
font-weight: bold;
|
||||
border-bottom: dotted gray 1px;
|
||||
margin-bottom: 0.5em;
|
||||
padding-bottom: 0.25em;
|
||||
}
|
||||
div.form-row {
|
||||
position: relative;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
div.toolForm {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
#canvas-area {
|
||||
position: absolute;
|
||||
top: 0; left: 305px; bottom: 0; right: 0;
|
||||
border: solid red 1px;
|
||||
overflow: none;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
|
||||
}
|
||||
.form-row-body {
|
||||
|
||||
}
|
||||
.form-row-clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
## <div id="shim" style="position: absolute; top: 0px; left: 0px; width: 10px; height: 10px; background: red; opacity: 0.1"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
<link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" />
|
||||
|
||||
<script type='text/javascript' src="/static/scripts/jquery.js"> </script>
|
||||
<script type='text/javascript' src="/static/scripts/jquery.dimensions.js"> </script>
|
||||
<script type='text/javascript' src="/static/scripts/jquery.ui.js"> </script>
|
||||
<script type='text/javascript' src="/static/scripts/jquery.blockUI.js"> </script>
|
||||
<script type='text/javascript' src="/static/scripts/jt.panels.js"> </script>
|
||||
<script>
|
||||
|
||||
$( function() {
|
||||
$.blockUI( "<b><img style='vertical-align: middle;' src='${h.url_for( '/static/style/data_running.gif' )}'/> Loading Galaxy Workflow Editor...</b>",
|
||||
{ border: "solid #AAAA66 1px", background: "#FFFFCC", padding: "20px", width: "auto" } );
|
||||
|
||||
make_left_panel( $("#tool-area"), $("#canvas-area"), $("#left-border" ) );
|
||||
// Insert div that covers everything when dragging the borders
|
||||
$("<div id='DD-helper' style='background: white; top: 0; left: 0; width: 100%; height: 100%; position: absolute; z-index: 9000;'></div>")
|
||||
.css("opacity", "0.01").appendTo("body").hide();
|
||||
// Show border visual cues
|
||||
$( "#left-border-inner" ).show();
|
||||
})
|
||||
|
||||
function notify() {
|
||||
$.unblockUI();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body, html
|
||||
{
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #eee;
|
||||
}
|
||||
#tool-area {
|
||||
background: url(${h.url_for('/static/style/menu_bg.png')});
|
||||
## border-top: solid #999 1px;
|
||||
position: absolute;
|
||||
top: 0px; left: 0; bottom: 0;
|
||||
width: 300px;
|
||||
overflow: scroll;
|
||||
}
|
||||
div.toolMenu {
|
||||
margin: 5px;
|
||||
}
|
||||
div.toolSectionPad {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 5px;
|
||||
font-size: 0px;
|
||||
}
|
||||
div.toolSectionDetailsInner {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
div.toolSectionTitle {
|
||||
padding-bottom: 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
div.toolTitle {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
margin-left: 16px;
|
||||
margin-right: 10px;
|
||||
display: list-item;
|
||||
list-style: square outside;
|
||||
}
|
||||
div.toolFormRow {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#canvas-area {
|
||||
## border-top: solid #999 1px;
|
||||
position: absolute;
|
||||
top: 0; left: 305px; bottom: 0; right: 0;
|
||||
overflow: none;
|
||||
}
|
||||
#left-border
|
||||
{
|
||||
position: absolute;
|
||||
top: 0; left: 300px; bottom: 0; right: 0;
|
||||
background: #eeeeee;
|
||||
border-left: solid #999 1px;
|
||||
border-right: solid #999 1px;
|
||||
padding-right: 1px;
|
||||
padding-left: 1px;
|
||||
width: 5px;
|
||||
z-index: 10000;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function add_node_for_tool( id ) {
|
||||
window.frames.canvas.add_node_for_tool( id );
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body scroll="no">
|
||||
## <div id="masthead">
|
||||
## <iframe name="galaxy_masthead" src="${h.url_for( controller='root', action='masthead' )}" width="38" height="100%" frameborder="0" scroll="no" style="margin: 0; border: 0 none; width: 100%; height: 38px; overflow: hidden;"> </iframe>
|
||||
## </div>
|
||||
<div id="tool-area">
|
||||
<div class="toolMenu">
|
||||
<div class="toolSectionList">
|
||||
%for i, section in enumerate( app.toolbox.sections ):
|
||||
%if i > 0:
|
||||
<div class="toolSectionPad"></div>
|
||||
%endif
|
||||
<div class="toolSectionTitle" id="title_${section.id}">
|
||||
<span>${section.name}</span>
|
||||
</div>
|
||||
<div id="${section.id}" class="toolSectionBody">
|
||||
<div class="toolSectionBg">
|
||||
%for tool in section.tools:
|
||||
%if not tool.hidden:
|
||||
<div class="toolTitle">
|
||||
## #if $tool.input_required
|
||||
## #set $link = $h.url_for( 'tool_runner', tool_id=$tool.id )
|
||||
## #else
|
||||
## #set $link = $h.url_for( $tool.action, ** $tool.get_static_param_values( $t ) )
|
||||
## #end if
|
||||
%if "[[" in tool.description and "]]" in tool.description:
|
||||
${tool.description.replace( '[[', '<a href="javascript:add_node_for_tool( ${tool.id} )">' % tool.id ).replace( "]]", "</a>" )}
|
||||
%elif tool.name:
|
||||
<a id="link-${tool.id}" href="javascript:add_node_for_tool( '${tool.id}' )">${tool.name}</a> ${tool.description}
|
||||
%else:
|
||||
<a id="link-${tool.id}" href="javascript:add_node_for_tool( '${tool.id}' )">${tool.description}</a>
|
||||
%endif
|
||||
</div>
|
||||
%endif
|
||||
%endfor
|
||||
</div>
|
||||
</div>
|
||||
%endfor
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="left-border"><div id="left-border-inner" style="display: none;"></div></div>
|
||||
<div id="canvas-area">
|
||||
<iframe name="canvas" width="100%" height="100%" frameborder="0" src="${h.url_for( action='canvas' )}">
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user