galaxy-commits
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
September 2013
- 1 participants
- 149 discussions
commit/galaxy-central: james_taylor: style: Restore margin to bottom of nav-tabs, normalize tab border colors
by commits-noreply@bitbucket.org 18 Sep '13
by commits-noreply@bitbucket.org 18 Sep '13
18 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/eb69169a04ef/
Changeset: eb69169a04ef
User: james_taylor
Date: 2013-09-18 20:13:36
Summary: style: Restore margin to bottom of nav-tabs, normalize tab border colors
Affected #: 3 files
diff -r 01f603a2179fce1cb39f5cfde973744585c73918 -r eb69169a04efb1fba610b943fd38a8ceb991d315 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -505,12 +505,12 @@
.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#303030}
.nav .nav-divider{height:1px;margin:7.5px 0;overflow:hidden;background-color:#e5e5e5}
.nav>li>a>img{max-width:none}
-.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:3px 3px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}
-.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}
+.nav-tabs{border-bottom:1px solid #bfbfbf}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:3px 3px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #bfbfbf}
+.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #bfbfbf;border-bottom-color:transparent;cursor:default}
.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}
@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:3px}
-.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}
-@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:3px 3px 0 0} .nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}
+.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #bfbfbf}
+@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #bfbfbf;border-radius:3px 3px 0 0} .nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}
.nav-pills>li{float:left}.nav-pills>li>a{border-radius:5px}
.nav-pills>li+li{margin-left:2px}
.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#303030}
@@ -518,8 +518,8 @@
.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}
@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}
.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:3px}
-.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}
-@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:3px 3px 0 0} .nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}
+.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #bfbfbf}
+@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #bfbfbf;border-radius:3px 3px 0 0} .nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}
.tabbable:before,.tabbable:after{content:" ";display:table;}
.tabbable:after{clear:both}
.tabbable:before,.tabbable:after{content:" ";display:table;}
@@ -756,9 +756,7 @@
.btn.active,.btn:active{color:inherit}
.dropdown-menu{max-width:auto}
input[type="checkbox"],input[type="radio"]{margin-left:0.5ex;margin-right:0.5ex}
-.nav-tabs{border-bottom:1px solid #bfbfbf}
-.nav-tabs>li>a:hover{border-color:#eee #eee #bfbfbf}
-.nav-tabs>.active>a,.nav-tabs>.active>a:hover{border:1px solid #bfbfbf;border-bottom-color:transparent}
+.nav-tabs{margin-bottom:15px}
a{text-decoration:underline}
label{font-weight:normal}
@font-face{font-family:'FontAwesome';src:url('../images/fonts/fontawesome-webfont.eot');src:url('../images/fonts/fontawesome-webfont.eot?#iefix') format('embedded-opentype'),url('../images/fonts/fontawesome-webfont.woff') format('woff'),url('../images/fonts/fontawesome-webfont.ttf') format('truetype');font-weight:normal;font-style:normal}.fa-icon,[class^="fa-icon-"],[class*=" fa-icon-"]{font-family:FontAwesome;font-size:1.1666666666666667em;background-image:none !important;background-position:0% 0%;background-repeat:repeat}
diff -r 01f603a2179fce1cb39f5cfde973744585c73918 -r eb69169a04efb1fba610b943fd38a8ceb991d315 static/style/src/less/galaxy_bootstrap/overrides.less
--- a/static/style/src/less/galaxy_bootstrap/overrides.less
+++ b/static/style/src/less/galaxy_bootstrap/overrides.less
@@ -57,15 +57,5 @@
// Tabs -- border color is hardcoded in navs.less, change to @btnBorder here
.nav-tabs {
- border-bottom: 1px solid @btn-default-border;
-}
-.nav-tabs > li > a {
- &:hover {
- border-color: @gray-lighter @gray-lighter @btn-default-border;
- }
-}
-.nav-tabs > .active > a,
-.nav-tabs > .active > a:hover {
- border: 1px solid @btn-default-border;
- border-bottom-color: transparent;
+ margin-bottom: 15px;
}
\ No newline at end of file
diff -r 01f603a2179fce1cb39f5cfde973744585c73918 -r eb69169a04efb1fba610b943fd38a8ceb991d315 static/style/src/less/galaxy_bootstrap/variables.less
--- a/static/style/src/less/galaxy_bootstrap/variables.less
+++ b/static/style/src/less/galaxy_bootstrap/variables.less
@@ -373,15 +373,15 @@
@nav-open-caret-border-color: @white;
// Tabs
-@nav-tabs-border-color: #ddd;
+@nav-tabs-border-color: @border-default-color;
@nav-tabs-link-hover-border-color: @gray-lighter;
@nav-tabs-active-link-hover-bg: @body-bg;
@nav-tabs-active-link-hover-color: @gray;
-@nav-tabs-active-link-hover-border-color: #ddd;
+@nav-tabs-active-link-hover-border-color: @border-default-color;
-@nav-tabs-justified-link-border-color: #ddd;
+@nav-tabs-justified-link-border-color: @border-default-color;
@nav-tabs-justified-active-link-border-color: @body-bg;
// Pills
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: james_taylor: Buttons and submit inputs always get the default .btn style
by commits-noreply@bitbucket.org 18 Sep '13
by commits-noreply@bitbucket.org 18 Sep '13
18 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/01f603a2179f/
Changeset: 01f603a2179f
User: james_taylor
Date: 2013-09-18 19:52:07
Summary: Buttons and submit inputs always get the default .btn style
Affected #: 5 files
diff -r 2d0bcb07596c4c688ed3908391d866831c65c042 -r 01f603a2179fce1cb39f5cfde973744585c73918 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1218,6 +1218,16 @@
select,input,textarea{font:inherit}
.form-row select,.form-row textarea,.form-row input[type="text"],.form-row input[type="file"],.form-row input[type="password"]{max-width:90%}
textarea,input[type="text"],input[type="password"]{font-size:12px;line-height:1.428571429;border:1px solid #aaa;padding:3px}
+input[type="submit"],button{display:inline-block;padding:4px 10px;margin-bottom:0;font-size:12px;font-weight:normal;line-height:1.428571429;text-align:center;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:3px;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;color:#333;background-color:#fff;border-color:#bfbfbf}input[type="submit"]:focus,button:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
+input[type="submit"]:hover,button:hover,input[type="submit"]:focus,button:focus{color:#333;text-decoration:none}
+input[type="submit"]:active,button:active,input[type="submit"].active,button.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}
+input[type="submit"].disabled,button.disabled,input[type="submit"][disabled],button[disabled],fieldset[disabled] input[type="submit"],fieldset[disabled] button{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}
+input[type="submit"] [class^="fa-icon-"],button [class^="fa-icon-"],input[type="submit"] [class*=" fa-icon-"],button [class*=" fa-icon-"]{display:inline;line-height:.6em}input[type="submit"] [class^="fa-icon-"].fa-icon-spin,button [class^="fa-icon-"].fa-icon-spin,input[type="submit"] [class*=" fa-icon-"].fa-icon-spin,button [class*=" fa-icon-"].fa-icon-spin{display:inline-block}
+input[type="submit"] [class^="fa-icon-"].pull-left.fa-icon-2x,button [class^="fa-icon-"].pull-left.fa-icon-2x,input[type="submit"] [class*=" fa-icon-"].pull-left.fa-icon-2x,button [class*=" fa-icon-"].pull-left.fa-icon-2x,input[type="submit"] [class^="fa-icon-"].pull-right.fa-icon-2x,button [class^="fa-icon-"].pull-right.fa-icon-2x,input[type="submit"] [class*=" fa-icon-"].pull-right.fa-icon-2x,button [class*=" fa-icon-"].pull-right.fa-icon-2x{margin-top:.35em}
+input[type="submit"] [class^="fa-icon-"].fa-icon-spin.icon-large,button [class^="fa-icon-"].fa-icon-spin.icon-large,input[type="submit"] [class*=" fa-icon-"].fa-icon-spin.icon-large,button [class*=" fa-icon-"].fa-icon-spin.icon-large{height:.75em}
+input[type="submit"]:hover,button:hover,input[type="submit"]:focus,button:focus,input[type="submit"]:active,button:active,input[type="submit"].active,button.active,.open .dropdown-toggleinput[type="submit"],.open .dropdown-togglebutton{color:#333;background-color:#ebebeb;border-color:#a1a1a1}
+input[type="submit"]:active,button:active,input[type="submit"].active,button.active,.open .dropdown-toggleinput[type="submit"],.open .dropdown-togglebutton{background-image:none}
+input[type="submit"].disabled,button.disabled,input[type="submit"][disabled],button[disabled],fieldset[disabled] input[type="submit"],fieldset[disabled] button,input[type="submit"].disabled:hover,button.disabled:hover,input[type="submit"][disabled]:hover,button[disabled]:hover,fieldset[disabled] input[type="submit"]:hover,fieldset[disabled] button:hover,input[type="submit"].disabled:focus,button.disabled:focus,input[type="submit"][disabled]:focus,button[disabled]:focus,fieldset[disabled] input[type="submit"]:focus,fieldset[disabled] button:focus,input[type="submit"].disabled:active,button.disabled:active,input[type="submit"][disabled]:active,button[disabled]:active,fieldset[disabled] input[type="submit"]:active,fieldset[disabled] button:active,input[type="submit"].disabled.active,button.disabled.active,input[type="submit"][disabled].active,button[disabled].active,fieldset[disabled] input[type="submit"].active,fieldset[disabled] button.active{background-color:#fff;border-color:#bfbfbf}
.search-query{display:inline-block;padding:4px;font-size:12px;line-height:1.428571429;color:#555;border:1px solid #aaa;padding-left:14px !important;padding-right:14px !important;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;max-width:auto}
.search-query:focus{border-color:rgba(24,132,218,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);outline:0;outline:thin dotted \9;}
.search-spinner{position:absolute;display:none;right:6px;top:9px}
diff -r 2d0bcb07596c4c688ed3908391d866831c65c042 -r 01f603a2179fce1cb39f5cfde973744585c73918 static/style/blue/sprite-fugue.png
Binary file static/style/blue/sprite-fugue.png has changed
diff -r 2d0bcb07596c4c688ed3908391d866831c65c042 -r 01f603a2179fce1cb39f5cfde973744585c73918 static/style/blue/sprite-history-buttons.png
Binary file static/style/blue/sprite-history-buttons.png has changed
diff -r 2d0bcb07596c4c688ed3908391d866831c65c042 -r 01f603a2179fce1cb39f5cfde973744585c73918 static/style/blue/sprite-history-states.png
Binary file static/style/blue/sprite-history-states.png has changed
diff -r 2d0bcb07596c4c688ed3908391d866831c65c042 -r 01f603a2179fce1cb39f5cfde973744585c73918 static/style/src/less/base.less
--- a/static/style/src/less/base.less
+++ b/static/style/src/less/base.less
@@ -660,6 +660,11 @@
padding: 3px;
}
+input[type="submit"], button {
+ .btn();
+ .btn-default();
+}
+
.search-query {
display: inline-block;
padding: 4px;
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Plugin framework: factor out page serving responsibility, add HookPluginManager subclass and PageServingPluginManager subclass; Visualization registry: inherit from PageServingPluginManager
by commits-noreply@bitbucket.org 18 Sep '13
by commits-noreply@bitbucket.org 18 Sep '13
18 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2d0bcb07596c/
Changeset: 2d0bcb07596c
User: carlfeberhard
Date: 2013-09-18 16:53:12
Summary: Plugin framework: factor out page serving responsibility, add HookPluginManager subclass and PageServingPluginManager subclass; Visualization registry: inherit from PageServingPluginManager
Affected #: 8 files
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 config/plugins/visualizations/graphview/config/graphview.xml
--- a/config/plugins/visualizations/graphview/config/graphview.xml
+++ b/config/plugins/visualizations/graphview/config/graphview.xml
@@ -16,5 +16,5 @@
<params><param type="dataset" var_name_in_template="hda" required="true">dataset_id</param></params>
- <template>graphview/templates/graphview.mako</template>
+ <template>graphview.mako</template></visualization>
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 config/plugins/visualizations/scatterplot/config/scatterplot.xml
--- a/config/plugins/visualizations/scatterplot/config/scatterplot.xml
+++ b/config/plugins/visualizations/scatterplot/config/scatterplot.xml
@@ -11,5 +11,5 @@
<params><param type="dataset" var_name_in_template="hda" required="true">dataset_id</param></params>
- <template>scatterplot/templates/scatterplot.mako</template>
+ <template>scatterplot.mako</template></visualization>
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -22,6 +22,8 @@
from galaxy.openid.providers import OpenIDProviders
from galaxy.tools.data_manager.manager import DataManagers
+from galaxy.web.base import pluginframework
+
import logging
log = logging.getLogger( __name__ )
@@ -123,8 +125,11 @@
# Load genome indexer tool.
load_genome_index_tools( self.toolbox )
# visualizations registry: associates resources with visualizations, controls how to render
- self.visualizations_registry = VisualizationsRegistry.from_config(
- self.config.visualizations_plugins_directory, self.config )
+ self.visualizations_registry = None
+ if self.config.visualizations_plugins_directory:
+ self.visualizations_registry = VisualizationsRegistry( self,
+ directories_setting=self.config.visualizations_plugins_directory,
+ template_cache_dir=self.config.template_cache )
# Load security policy.
self.security_agent = self.model.security_agent
self.host_security_agent = galaxy.security.HostAgent( model=self.security_agent.model, permitted_actions=self.security_agent.permitted_actions )
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -294,9 +294,7 @@
self.fluent_log = string_as_bool( kwargs.get( 'fluent_log', False ) )
self.fluent_host = kwargs.get( 'fluent_host', 'localhost' )
self.fluent_port = int( kwargs.get( 'fluent_port', 24224 ) )
- # PLUGINS:
- self.plugin_frameworks = []
- # visualization framework
+ # visualization plugin framework
self.visualizations_plugins_directory = kwargs.get( 'visualizations_plugins_directory', None )
@property
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/visualization/registry.py
--- a/lib/galaxy/visualization/registry.py
+++ b/lib/galaxy/visualization/registry.py
@@ -39,9 +39,10 @@
"""
# ------------------------------------------------------------------- the registry
-class VisualizationsRegistry( pluginframework.PluginFramework ):
+class VisualizationsRegistry( pluginframework.PageServingPluginManager ):
"""
Main responsibilities are:
+ - discovering visualization plugins in the filesystem
- testing if an object has a visualization that can be applied to it
- generating a link to controllers.visualization.render with
the appropriate params
@@ -58,31 +59,79 @@
'sweepster',
'phyloviz'
]
- #: directories under plugin_directory that aren't plugins
- non_plugin_directories = []
- def __init__( self, registry_filepath, template_cache_dir ):
- super( VisualizationsRegistry, self ).__init__( registry_filepath, 'visualizations', template_cache_dir )
+ def __str__( self ):
+ return self.__class__.__name__
+ def __init__( self, app, **kwargs ):
+ self.config_parser = VisualizationsConfigParser()
+ super( VisualizationsRegistry, self ).__init__( app, 'visualizations', **kwargs )
# what to use to parse query strings into resources/vars for the template
self.resource_parser = ResourceParser()
log.debug( '%s loaded', str( self ) )
- def load_configuration( self ):
+ def is_plugin( self, plugin_path ):
"""
- Builds the registry by parsing the `config/*.xml` files for every plugin
- in ``get_plugin_directories`` and stores the results in ``self.listings``.
+ Determines whether the given filesystem path contains a plugin.
- ..note::
- This could be used to re-load a new configuration without restarting
- the instance.
+ In this base class, all sub-directories are considered plugins.
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the
+ potential plugin
+ :rtype: bool
+ :returns: True if the path contains a plugin
"""
- try:
- self.listings = VisualizationsConfigParser.parse( self.get_plugin_directories() )
+ # plugin_path must be a directory, have a config dir
+ if not os.path.isdir( plugin_path ):
+ return False
+ if not 'config' in os.listdir( plugin_path ):
+ return False
+ expected_config_filename = '%s.xml' %( os.path.split( plugin_path )[1] )
+ if not os.path.isfile( os.path.join( plugin_path, 'config', expected_config_filename ) ):
+ return False
+ return True
- except Exception, exc:
- log.exception( 'Error parsing visualizations plugins %s', self.plugin_directories )
- raise
+ def load_plugin( self, plugin_path ):
+ """
+ Create the visualization plugin object, parse its configuration file,
+ and return it.
+
+ Plugin bunches are decorated with:
+ * config_file : the path to this visualization's config file
+ * config : the parsed configuration for this visualization
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the plugin
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ #TODO: possibly move this after the config parsing to allow config to override?
+ plugin = super( VisualizationsRegistry, self ).load_plugin( plugin_path )
+
+ # config file is required, otherwise skip this visualization
+ plugin[ 'config_file' ] = os.path.join( plugin_path, 'config', ( plugin.name + '.xml' ) )
+ config = self.config_parser.parse_file( plugin.config_file )
+ if not config:
+ return None
+ plugin[ 'config' ] = config
+
+ return plugin
+
+ # -- getting resources for visualization templates from link query strings --
+ # -- building links to visualizations from objects --
+ def get_visualizations( self, trans, target_object ):
+ """
+ Get the names of visualizations usable on the `target_object` and
+ the urls to call in order to render the visualizations.
+ """
+ #TODO:?? a list of objects? YAGNI?
+ applicable_visualizations = []
+ for vis_name in self.plugins:
+ url_data = self.get_visualization( trans, vis_name, target_object )
+ if url_data:
+ applicable_visualizations.append( url_data )
+ return applicable_visualizations
def get_visualization( self, trans, visualization_name, target_object ):
"""
@@ -90,12 +139,11 @@
`visualization_name` if it's applicable to `target_object` or
`None` if it's not.
"""
- # a little weird to pass trans because this registry is part of the trans.app
- listing_data = self.listings.get( visualization_name, None )
- if not listing_data:
+ visualization = self.plugins.get( visualization_name, None )
+ if not visualization:
return None
- data_sources = listing_data[ 'data_sources' ]
+ data_sources = visualization.config[ 'data_sources' ]
for data_source in data_sources:
# currently a model class is required
model_class = data_source[ 'model_class' ]
@@ -109,11 +157,11 @@
param_data = data_source[ 'to_params' ]
url = self.get_visualization_url( trans, target_object, visualization_name, param_data )
- link_text = listing_data.get( 'link_text', None )
+ link_text = visualization.config.get( 'link_text', None )
if not link_text:
# default to visualization name, titlecase, and replace underscores
link_text = visualization_name.title().replace( '_', ' ' )
- render_location = listing_data.get( 'render_location' )
+ render_location = visualization.config.get( 'render_location' )
# remap some of these vars for direct use in ui.js, PopupMenu (e.g. text->html)
return {
'href' : url,
@@ -123,25 +171,12 @@
return None
- # -- building links to visualizations from objects --
- def get_visualizations( self, trans, target_object ):
- """
- Get the names of visualizations usable on the `target_object` and
- the urls to call in order to render the visualizations.
- """
- #TODO:?? a list of objects? YAGNI?
- applicable_visualizations = []
- for vis_name in self.listings:
- url_data = self.get_visualization( trans, vis_name, target_object )
- if url_data:
- applicable_visualizations.append( url_data )
- return applicable_visualizations
-
def is_object_applicable( self, trans, target_object, data_source_tests ):
"""
Run a visualization's data_source tests to find out if
it be applied to the target_object.
"""
+ #log.debug( 'is_object_applicable( self, trans, %s, %s )', target_object, data_source_tests )
for test in data_source_tests:
test_type = test[ 'type' ]
result_type = test[ 'result_type' ]
@@ -164,7 +199,6 @@
if test_fn( target_object, test_result ):
#log.debug( 'test passed' )
return True
-
return False
def get_visualization_url( self, trans, target_object, visualization_name, param_data ):
@@ -219,9 +253,9 @@
Both `params` and `param_modifiers` default to an empty dictionary.
"""
- visualization = self.listings.get( visualization_name )
- expected_params = visualization.get( 'params', {} )
- param_modifiers = visualization.get( 'param_modifiers', {} )
+ visualization = self.plugins.get( visualization_name )
+ expected_params = visualization.config.get( 'params', {} )
+ param_modifiers = visualization.config.get( 'param_modifiers', {} )
return ( expected_params, param_modifiers )
def query_dict_to_resources( self, trans, controller, visualization_name, query_dict ):
@@ -259,13 +293,6 @@
"""
VALID_RENDER_LOCATIONS = [ 'galaxy_main', '_top', '_blank' ]
- @classmethod
- def parse( cls, plugin_directories, debug=False ):
- """
- Static class interface.
- """
- return cls( debug ).parse_plugins( plugin_directories )
-
def __init__( self, debug=False ):
self.debug = debug
@@ -274,58 +301,19 @@
self.param_parser = ParamParser()
self.param_modifier_parser = ParamModifierParser()
- def parse_plugins( self, plugin_directories ):
- """
- Parses the config files for each plugin sub-dir in `base_path`.
-
- :param plugin_directories: a list of paths to enabled plugins.
-
- :returns: registry data in dictionary form
- """
- returned = {}
- for plugin_path in plugin_directories:
- returned.update( self.parse_plugin( plugin_path ) )
- return returned
-
- def parse_plugin( self, plugin_path ):
- """
- Parses any XML files in ``<plugin_path>/config``.
-
- If an error occurs while parsing a visualizations entry, it is skipped.
- :returns: registry data in dictionary form
- ..note::
- assumes config files are in a 'config' sub-dir of each plugin
- """
- returned = {}
-
- plugin_config_path = os.path.join( plugin_path, 'config' )
- if not os.path.isdir( plugin_config_path ):
- return returned
-
- for xml_filepath in glob.glob( os.path.join( plugin_config_path, '*.xml' ) ):
- try:
- visualization_name, visualization = self.parse_file( xml_filepath )
- # skip vis' with parsing errors - don't shutdown the startup
- except ParsingException, parse_exc:
- log.error( 'Skipped visualization config "%s" due to parsing errors: %s',
- xml_filepath, str( parse_exc ), exc_info=self.debug )
-
- if visualization:
- returned[ visualization_name ] = visualization
- log.debug( 'Visualization config loaded for: %s', visualization_name )
-
- return returned
-
def parse_file( self, xml_filepath ):
"""
Parse the given XML file for visualizations data.
:returns: tuple of ( `visualization_name`, `visualization` )
"""
- xml_tree = galaxy.util.parse_xml( xml_filepath )
- visualization_conf = xml_tree.getroot()
- visualization_name = visualization_conf.get( 'name' )
- visualization = self.parse_visualization( visualization_conf )
- return visualization_name, visualization
+ try:
+ xml_tree = galaxy.util.parse_xml( xml_filepath )
+ visualization = self.parse_visualization( xml_tree.getroot() )
+ return visualization
+ # skip vis' with parsing errors - don't shutdown the startup
+ except ParsingException, parse_exc:
+ log.exception( 'Skipped visualization config "%s" due to parsing errors', xml_filepath )
+ return None
def parse_visualization( self, xml_tree ):
"""
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/web/base/pluginframework.py
--- a/lib/galaxy/web/base/pluginframework.py
+++ b/lib/galaxy/web/base/pluginframework.py
@@ -1,150 +1,106 @@
"""
Base class for plugins - frameworks or systems that may:
+ * add code at startup
+ * allow hooks to be called
+and base class for plugins that:
* serve static content
* serve templated html
* have some configuration at startup
"""
import os.path
-import glob
import sys
+import imp
import pkg_resources
pkg_resources.require( 'MarkupSafe' )
pkg_resources.require( 'Mako' )
import mako
-from galaxy.util import listify
+from galaxy import util
+from galaxy.util import odict
+from galaxy.util import bunch
import logging
log = logging.getLogger( __name__ )
# ============================================================================= exceptions
-class PluginFrameworkException( Exception ):
+class PluginManagerException( Exception ):
"""Base exception for plugin frameworks.
"""
pass
-class PluginFrameworkConfigException( PluginFrameworkException ):
+class PluginManagerConfigException( PluginManagerException ):
"""Exception for plugin framework configuration errors.
"""
pass
-class PluginFrameworkStaticException( PluginFrameworkException ):
- """Exception for plugin framework static directory set up errors.
- """
- pass
-class PluginFrameworkTemplateException( PluginFrameworkException ):
- """Exception for plugin framework template directory
- and template rendering errors.
- """
- pass
# ============================================================================= base
-class PluginFramework( object ):
+class PluginManager( object ):
"""
- Plugins are files/directories living outside the Galaxy ``lib`` directory
- that serve static files (css, js, images, etc.), use and serve mako templates,
- and have some configuration to control the rendering.
+ Plugins represents an section of code that is not tracked in the
+ Galaxy repository, allowing the addition of custom code to a Galaxy
+ installation without changing the code base.
- A plugin framework sets up all the above components.
+ A PluginManager discovers and manages these plugins.
+
+ This is an non-abstract class but it's usefulness is limited and is meant
+ to be inherited.
"""
- #: does the class need a config file(s) to be parsed?
- has_config = True
- #: does the class need static files served?
- serves_static = True
- #: does the class need template files served?
- serves_templates = True
- #TODO: allow plugin mako inheritance from existing ``/templates`` files
- #uses_galaxy_templates = True
- #TODO: possibly better as instance var (or a combo)
- #: the directories in ``plugin_directory`` with basenames listed here will
- #: be ignored for config, static, and templates
- non_plugin_directories = []
- # ------------------------------------------------------------------------- setup
- @classmethod
- def from_config( cls, config_plugin_directory, config ):
+ def __init__( self, app, directories_setting=None, skip_bad_plugins=True, **kwargs ):
"""
- Set up the framework based on data from some config object by:
- * constructing it's absolute plugin_directory filepath
- * getting a template_cache
- * and appending itself to the config object's ``plugin_frameworks`` list
+ Set up the manager and load all plugins.
- .. note::
- precondition: config obj should have attributes:
- root, template_cache, and (list) plugin_frameworks
+ :type app: UniverseApplication
+ :param app: the application (and it's configuration) using this manager
+ :type directories_setting: string (default: None)
+ :param directories_setting: the filesystem path (or paths)
+ to search for plugins. Can be CSV string of paths. Will be treated as
+ absolute if a path starts with '/', relative otherwise.
+ :type skip_bad_plugins: boolean (default: True)
+ :param skip_bad_plugins: whether to skip plugins that cause
+ exceptions when loaded or to raise that exception
"""
- # currently called from (base) app.py - defined here to allow override if needed
- if not config_plugin_directory:
- return None
- try:
- # create the plugin path and if plugin dir begins with '/' assume absolute path
- full_plugin_filepath = os.path.join( config.root, config_plugin_directory )
- if config_plugin_directory.startswith( os.path.sep ):
- full_plugin_filepath = config_plugin_directory
- if not os.path.exists( full_plugin_filepath ):
- raise PluginFrameworkException( 'Plugin path not found: %s' %( full_plugin_filepath ) )
+ log.debug( 'PluginManager.init: %s, %s', directories_setting, kwargs )
+ self.directories = []
+ self.skip_bad_plugins = skip_bad_plugins
+ self.plugins = odict.odict()
- template_cache = config.template_cache if cls.serves_static else None
- plugin = cls( full_plugin_filepath, template_cache )
+ self.directories = self.parse_directories_setting( app.config.root, directories_setting )
+ #log.debug( '\t directories: %s', self.directories )
- config.plugin_frameworks.append( plugin )
- return plugin
+ self.load_configuration()
+ self.load_plugins()
- except PluginFrameworkException, plugin_exc:
- log.exception( "Error loading framework %s. Skipping...", cls.__class__.__name__ )
- return None
+ def parse_directories_setting( self, galaxy_root, directories_setting ):
+ """
+ Parse the ``directories_setting`` into a list of relative or absolute
+ filesystem paths that will be searched to discover plugins.
- def __str__( self ):
- return '%s(%s)' %( self.__class__.__name__, self.plugin_directories )
+ :type galaxy_root: string
+ :param galaxy_root: the root path of this galaxy installation
+ :type directories_setting: string (default: None)
+ :param directories_setting: the filesystem path (or paths)
+ to search for plugins. Can be CSV string of paths. Will be treated as
+ absolute if a path starts with '/', relative otherwise.
+ :rtype: list of strings
+ :returns: list of filesystem paths
+ """
+ directories = []
+ if not directories_setting:
+ return directories
- def __init__( self, plugin_directories, name=None, template_cache_dir=None, debug=False, assert_exists=True ):
- """
- :type plugin_directories: string or list
- :param plugin_directories: the base directory where plugin code is kept
- :type name: (optional) string (default: None)
- :param name: the name of this plugin
- (that will appear in url pathing, etc.)
- :type template_cache_dir: (optional) string (default: None)
- :param template_cache_dir: the cache directory to store compiled mako
- :type assert_exists: (optional) bool (default: False)
- :param assert_exists: If True, each configured plugin directory must exist.
- """
- self.plugin_directories = listify( plugin_directories )
- if assert_exists:
- for plugin_directory in self.plugin_directories:
- if not os.path.isdir( plugin_directory ):
- raise PluginFrameworkException( 'Framework plugin directory not found: %s, %s'
- % ( self.__class__.__name__, plugin_directory ) )
+ for directory in util.listify( directories_setting ):
+ directory = directory.strip()
+ if directory.startswith( '/' ):
+ directory = os.path.join( galaxy_root, directory )
+ if not os.path.exists( directory ):
+ log.warn( '%s, directory not found: %s', self, directory )
+ continue
+ directories.append( directory )
+ return directories
- #TODO: or pass in from config
- self.name = name or os.path.basename( self.plugin_directories[0] )
-
- if self.has_config:
- self.load_configuration()
- # set_up_static_urls will be called during the static middleware creation (if serves_static)
- if self.serves_templates:
- self.set_up_templates( template_cache_dir )
-
- def get_plugin_directories( self ):
- """
- Return the plugin directory paths for this plugin.
-
- Gets any directories within ``plugin_directory`` that are directories
- themselves and whose ``basename`` is not in ``plugin_directory``.
- """
- # could instead explicitly list on/off in master config file
- for plugin_directory in self.plugin_directories:
- for plugin_path in glob.glob( os.path.join( plugin_directory, '*' ) ):
- if not os.path.isdir( plugin_path ):
- continue
-
- if os.path.basename( plugin_path ) in self.non_plugin_directories:
- continue
-
- yield plugin_path
-
- # ------------------------------------------------------------------------- config
def load_configuration( self ):
"""
Override to load some framework/plugin specifc configuration.
@@ -152,6 +108,348 @@
# Abstract method
return True
+ def load_plugins( self ):
+ """
+ Search ``self.directories`` for potential plugins, load them, and cache
+ in ``self.plugins``.
+ :rtype: odict
+ :returns: ``self.plugins``
+ """
+ for plugin_path in self.find_plugins():
+ try:
+ plugin = self.load_plugin( plugin_path )
+ if not plugin:
+ log.warn( '%s, plugin load failed: %s. Skipping...', self, plugin_path )
+ #NOTE: prevent silent, implicit overwrite here (two plugins in two diff directories)
+ #TODO: overwriting may be desired
+ elif plugin.name in self.plugins:
+ log.warn( '%s, plugin with name already exists: %s. Skipping...', self, plugin.name )
+ else:
+ self.plugins[ plugin.name ] = plugin
+ log.info( '%s, loaded plugin: %s', self, plugin.name )
+
+ except Exception, exc:
+ if not self.skip_bad_plugins:
+ raise
+ log.exception( 'Plugin loading raised exception: %s. Skipping...', plugin_path )
+
+ return self.plugins
+
+ def find_plugins( self ):
+ """
+ Return the directory paths of plugins within ``self.directories``.
+
+ Paths are considered a plugin path if they pass ``self.is_plugin``.
+ :rtype: string generator
+ :returns: paths of valid plugins
+ """
+ # due to the ordering of listdir, there is an implicit plugin loading order here
+ # could instead explicitly list on/off in master config file
+ for directory in self.directories:
+ for plugin_dir in os.listdir( directory ):
+ plugin_path = os.path.join( directory, plugin_dir )
+ if self.is_plugin( plugin_path ):
+ yield plugin_path
+
+ def is_plugin( self, plugin_path ):
+ """
+ Determines whether the given filesystem path contains a plugin.
+
+ In this base class, all sub-directories are considered plugins.
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the
+ potential plugin
+ :rtype: bool
+ :returns: True if the path contains a plugin
+ """
+ if not os.path.isdir( plugin_path ):
+ return False
+ return True
+
+ def load_plugin( self, plugin_path ):
+ """
+ Create, load, and/or initialize the plugin and return it.
+
+ Plugin bunches are decorated with:
+ * name : the plugin name
+ * path : the plugin path
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the plugin
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ plugin = bunch.Bunch(
+ #TODO: need a better way to define plugin names
+ # pro: filesystem name ensures uniqueness
+ # con: rel. inflexible
+ name = os.path.split( plugin_path )[1],
+ path = plugin_path
+ )
+ return plugin
+
+
+# ============================================================================= plugin managers using hooks
+class HookPluginManager( PluginManager ):
+ """
+ A hook plugin is a directory containing python modules or packages that:
+ * allow creating, including, and running custom code at specific 'hook'
+ points/events
+ * are not tracked in the Galaxy repository and allow adding custom code
+ to a Galaxy installation
+
+ A HookPluginManager imports the plugin code needed and calls the plugin's
+ hook functions at the specified time.
+ """
+ #: the python file that will be imported - hook functions should be contained here
+ loading_point_filename = 'plugin.py'
+ hook_fn_prefix = 'hook_'
+
+ def is_plugin( self, plugin_path ):
+ """
+ Determines whether the given filesystem path contains a hookable plugin.
+
+ All sub-directories that contain ``loading_point_filename`` are considered
+ plugins.
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the
+ potential plugin
+ :rtype: bool
+ :returns: True if the path contains a plugin
+ """
+ if not super( HookPluginManager, self ).is_plugin( plugin_path ):
+ return False
+ #TODO: possibly switch to <plugin.name>.py or __init__.py
+ if self.loading_point_filename not in os.listdir( plugin_path ):
+ return False
+ return True
+
+ def load_plugin( self, plugin_path ):
+ """
+ Import the plugin ``loading_point_filename`` and attach to the plugin bunch.
+
+ Plugin bunches are decorated with:
+ * name : the plugin name
+ * path : the plugin path
+ * module : the plugin code
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the plugin
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ plugin = super( HookPluginManager, self ).load_plugin( plugin_path )
+
+ loading_point_name = self.loading_point_filename[:-3]
+ plugin[ 'module' ] = self.import_plugin_module( loading_point_name, plugin )
+ return plugin
+
+ def import_plugin_module( self, loading_point_name, plugin, import_as=None ):
+ """
+ Import the plugin code and cache the module in the plugin object.
+
+ :type loading_point_name: string
+ :param loading_point_name: name of the python file to import (w/o extension)
+ :type plugin: ``util.bunch.Bunch``
+ :param plugin: the plugin containing the template to render
+ :type import_as: string
+ :param import_as: namespace to use for imported module
+ This will be prepended with the ``__name__`` of this file.
+ Defaults to ``plugin.name``
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ # add this name to import_as (w/ default to plugin.name) to prevent namespace pollution in sys.modules
+ import_as = '%s.%s' %( __name__, ( import_as or plugin.name ) )
+ module_file, pathname, description = imp.find_module( loading_point_name, [ plugin.path ] )
+ try:
+ #TODO: hate this hack but only way to get package imports inside the plugin to work?
+ sys.path.append( plugin.path )
+ # sys.modules will now have import_as in it's list
+ module = imp.load_module( import_as, module_file, pathname, description )
+ finally:
+ module_file.close()
+ if plugin.path in sys.path:
+ sys.path.remove( plugin.path )
+ return module
+
+ def run_hook( self, hook_name, *args, **kwargs ):
+ """
+ Search all plugins for a function named ``hook_fn_prefix`` + ``hook_name``
+ and run it passing in args and kwargs.
+
+ :type hook_name: string
+ :param hook_name: name (suffix) of the hook to run
+ :rtype: 2-tuple containing (list, dict)
+ :returns: (possibly modified) args, kwargs
+ """
+ #TODO: is hook prefix necessary?
+ #TODO: could be made more efficient if cached by hook_name in the manager on load_plugin
+ # (low maint. overhead since no dynamic loading/unloading of plugins)
+ hook_fn_name = ''.join([ self.hook_fn_prefix, hook_name ])
+ for plugin_name, plugin in self.plugins.items():
+ hook_fn = getattr( plugin.module, hook_fn_name, None )
+
+ if hook_fn and hasattr( hook_fn, '__call__' ):
+ try:
+ #log.debug( 'calling %s from %s(%s)', hook_fn.func_name, plugin.name, plugin.module )
+ hook_fn( *args, **kwargs )
+ except Exception, exc:
+ # fail gracefully and continue with other plugins
+ log.exception( 'Hook function "%s" failed for plugin "%s"', hook_name, plugin.name )
+
+ # may have been altered by hook fns, return in order to act like filter
+ return args, kwargs
+
+
+# ============================================================================= exceptions
+class PluginManagerStaticException( PluginManagerException ):
+ """Exception for plugin framework static directory set up errors.
+ """
+ pass
+class PluginManagerTemplateException( PluginManagerException ):
+ """Exception for plugin framework template directory
+ and template rendering errors.
+ """
+ pass
+
+
+# ============================================================================= base
+class PageServingPluginManager( PluginManager ):
+ """
+ Page serving plugins are files/directories that:
+ * are not tracked in the Galaxy repository and allow adding custom code
+ to a Galaxy installation
+ * serve static files (css, js, images, etc.),
+ * render templates
+
+ A PageServingPluginManager sets up all the above components.
+ """
+ #TODO: I'm unclear of the utility of this class - it prob. will only have one subclass (vis reg). Fold into?
+
+ #: does the class need static files served?
+ serves_static = True
+ #: does the class need template files served?
+ serves_templates = True
+ #: default number of templates to search for plugin template lookup
+ DEFAULT_TEMPLATE_COLLECTION_SIZE = 10
+ #: default encoding of plugin templates
+ DEFAULT_TEMPLATE_ENCODING = 'utf-8'
+
+ def __init__( self, app, base_url, template_cache_dir=None, **kwargs ):
+ """
+ Set up the manager and load all plugins.
+
+ :type app: UniverseApplication
+ :param app: the application (and it's configuration) using this manager
+ :type base_url: string
+ :param base_url: url to prefix all plugin urls with
+ :type template_cache_dir: string
+ :param template_cache_dir: filesytem path to the directory where cached
+ templates are kept
+ """
+ self.base_url = base_url
+ self.template_cache_dir = template_cache_dir
+
+ super( PageServingPluginManager, self ).__init__( app, **kwargs )
+
+ def is_plugin( self, plugin_path ):
+ """
+ Determines whether the given filesystem path contains a plugin.
+
+ If the manager ``serves_templates`` and a sub-directory contains another
+ sub-directory named 'templates' it's considered valid.
+ If the manager ``serves_static`` and a sub-directory contains another
+ sub-directory named 'static' it's considered valid.
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the
+ potential plugin
+ :rtype: bool
+ :returns: True if the path contains a plugin
+ """
+ if not os.path.isdir( plugin_path ):
+ return False
+ #TODO: this is not reliable and forces the inclusion of empty dirs in some situations
+ if self.serves_templates and not 'templates' in os.listdir( plugin_path ):
+ return False
+ if self.serves_static and not 'static' in os.listdir( plugin_path ):
+ return False
+ return True
+
+ def load_plugin( self, plugin_path ):
+ """
+ Create the plugin and decorate with static and/or template paths and urls.
+
+ Plugin bunches are decorated with:
+ * name : the plugin name
+ * path : the plugin path
+ * base_url : a url to the plugin
+
+ :type plugin_path: string
+ :param plugin_path: relative or absolute filesystem path to the plugin
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ plugin = super( PageServingPluginManager, self ).load_plugin( plugin_path )
+ #TODO: urlencode?
+ plugin[ 'base_url' ] = '/'.join([ self.base_url, plugin.name ])
+ plugin = self._set_up_static_plugin( plugin )
+ plugin = self._set_up_template_plugin( plugin )
+
+ return plugin
+
+ def _set_up_static_plugin( self, plugin ):
+ """
+ Decorate the plugin with paths and urls needed to serve static content.
+
+ Plugin bunches are decorated with:
+ * serves_static : whether this plugin will serve static content
+
+ If the plugin path contains a 'static' sub-dir, the following are added:
+ * static_path : the filesystem path to the static content
+ * static_url : the url to use when serving static content
+
+ :type plugin: ``util.bunch.Bunch``
+ :param plugin: the plugin to decorate
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ plugin[ 'serves_static' ] = False
+ static_path = os.path.join( plugin.path, 'static' )
+ if self.serves_static and os.path.isdir( static_path ):
+ plugin.serves_static = True
+ plugin[ 'static_path' ] = static_path
+ plugin[ 'static_url' ] = '/'.join([ plugin.base_url, 'static' ])
+ return plugin
+
+ def _set_up_template_plugin( self, plugin ):
+ """
+ Decorate the plugin with paths needed to fill templates.
+
+ Plugin bunches are decorated with:
+ * serves_templates : whether this plugin will use templates
+
+ If the plugin path contains a 'static' sub-dir, the following are added:
+ * template_path : the filesystem path to the template sub-dir
+ * template_lookup : the (currently Mako) TemplateLookup used to search
+ for templates
+
+ :type plugin: ``util.bunch.Bunch``
+ :param plugin: the plugin to decorate
+ :rtype: ``util.bunch.Bunch``
+ :returns: the loaded plugin object
+ """
+ plugin[ 'serves_templates' ] = False
+ template_path = os.path.join( plugin.path, 'templates' )
+ if self.serves_templates and os.path.isdir( template_path ):
+ plugin.serves_templates = True
+ plugin[ 'template_path' ] = template_path
+ plugin[ 'template_lookup' ] = self.build_plugin_template_lookup( plugin )
+ return plugin
+
# ------------------------------------------------------------------------- serving static files
def get_static_urls_and_paths( self ):
"""
@@ -160,81 +458,63 @@
same files.
Meant to be passed to a Static url map.
+
+ :rtype: list of 2-tuples
+ :returns: all urls and paths for each plugin serving static content
"""
- url_and_paths = []
# called during the static middleware creation (buildapp.py, wrap_in_static)
-
- # NOTE: this only searches for static dirs two levels deep (i.e. <plugin_directory>/<plugin-name>/static)
- for plugin_path in self.get_plugin_directories():
- # that path is a plugin, search for subdirs named static in THAT dir
- plugin_static_path = os.path.join( plugin_path, 'static' )
- if not os.path.isdir( plugin_static_path ):
- continue
-
- # build a url for that static subdir and create a Static urlmap entry for it
- plugin_name = os.path.splitext( os.path.basename( plugin_path ) )[0]
- plugin_url = self.name + '/' + plugin_name + '/static'
- url_and_paths.append( ( plugin_url, plugin_static_path ) )
-
- return url_and_paths
+ urls_and_paths = []
+ for plugin in self.plugins.values():
+ if plugin.serves_static:
+ urls_and_paths.append( ( plugin.static_url, plugin.static_path ) )
+ return urls_and_paths
# ------------------------------------------------------------------------- templates
- def set_up_templates( self, template_cache_dir ):
+ def build_plugin_template_lookup( self, plugin ):
"""
- Add a ``template_lookup`` attribute to the framework that can be passed
- to the mako renderer to find templates.
+ Builds the object that searches for templates (cached or not) when rendering.
+
+ :type plugin: ``util.bunch.Bunch``
+ :param plugin: the plugin containing the templates
+ :rtype: ``Mako.lookup.TemplateLookup``
+ :returns: template lookup for this plugin
"""
- if not template_cache_dir:
- raise PluginFrameworkTemplateException( 'Plugins that serve templates require a template_cache_dir' )
- self.template_lookup = self._create_mako_template_lookup( template_cache_dir, self._get_template_paths() )
- return self.template_lookup
+ if not plugin.serves_templates:
+ return None
+ template_lookup = self._create_mako_template_lookup( self.template_cache_dir, plugin.template_path )
+ return template_lookup
- def _get_template_paths( self ):
- """
- Get the paths that will be searched for templates.
- """
- return self.plugin_directories
-
- def _create_mako_template_lookup( self, cache_dir, paths, collection_size=500, output_encoding='utf-8' ):
+ def _create_mako_template_lookup( self, cache_dir, paths,
+ collection_size=DEFAULT_TEMPLATE_COLLECTION_SIZE, output_encoding=DEFAULT_TEMPLATE_ENCODING ):
"""
Create a ``TemplateLookup`` with defaults.
+
+ :rtype: ``Mako.lookup.TemplateLookup``
+ :returns: all urls and paths for each plugin serving static content
"""
+ #TODO: possible to add galaxy/templates into the lookup here?
return mako.lookup.TemplateLookup(
directories = paths,
module_directory = cache_dir,
collection_size = collection_size,
output_encoding = output_encoding )
- #TODO: do we want to remove trans and app from the plugin template context?
- def fill_template( self, trans, template_filename, **kwargs ):
+ def fill_template( self, trans, plugin, template_filename, **kwargs ):
"""
- Pass control over to trans and render the ``template_filename``.
+ Pass control over to trans and render ``template_filename``.
+
+ :type trans: ``galaxy.web.framework.GalaxyWebTransaction``
+ :param trans: transaction doing the rendering
+ :type plugin: ``util.bunch.Bunch``
+ :param plugin: the plugin containing the template to render
+ :type template_filename: string
+ :param template_filename: the path of the template to render relative to
+ ``plugin.template_path``
+ :returns: rendered template
"""
# defined here to be overridden
- return trans.fill_template( template_filename, template_lookup=self.template_lookup, **kwargs )
+ return trans.fill_template( template_filename, template_lookup=plugin.template_lookup, **kwargs )
- def fill_template_with_plugin_imports( self, trans, template_filename, **kwargs ):
- """
- Returns a rendered plugin template but allows importing modules from inside
- the plugin directory within the template.
-
- ..example:: I.e. given this layout for a plugin:
- bler/
- template/
- bler.mako
- static/
- conifg/
- my_script.py
- this version of `fill_template` allows `bler.mako` to call `import my_script`.
- """
- try:
- plugin_path = os.path.dirname( os.path.dirname( template_filename ) )
- sys.path.append( plugin_path )
- filled_template = self.fill_template( trans, template_filename, **kwargs )
-
- finally:
- sys.path.remove( plugin_path )
-
- return filled_template
-
- #TODO: could add plugin template helpers here
+ #TODO: add fill_template fn that is able to load extra libraries beforehand (and remove after)
+ #TODO: add template helpers specific to the plugins
+ #TODO: some sort of url_for for these plugins
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/webapps/galaxy/buildapp.py
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -193,7 +193,8 @@
if kwargs.get( 'middleware', True ):
webapp = wrap_in_middleware( webapp, global_conf, **kwargs )
if asbool( kwargs.get( 'static_enabled', True ) ):
- webapp = wrap_in_static( webapp, global_conf, plugin_frameworks=app.config.plugin_frameworks, **kwargs )
+ webapp = wrap_in_static( webapp, global_conf, plugin_frameworks=[ app.visualizations_registry ], **kwargs )
+ #webapp = wrap_in_static( webapp, global_conf, plugin_frameworks=None, **kwargs )
if asbool(kwargs.get('pack_scripts', False)):
pack_scripts()
# Close any pooled database connections before forking
@@ -362,12 +363,13 @@
# wrap any static dirs for plugins
plugin_frameworks = plugin_frameworks or []
- for static_serving_framework in ( framework for framework in plugin_frameworks if framework.serves_static ):
- # invert control to each plugin for finding their own static dirs
- for plugin_url, plugin_static_path in static_serving_framework.get_static_urls_and_paths():
- plugin_url = '/plugins/' + plugin_url
- urlmap[( plugin_url )] = Static( plugin_static_path, cache_time )
- log.debug( 'added url, path to static middleware: %s, %s', plugin_url, plugin_static_path )
+ for framework in plugin_frameworks:
+ if framework and framework.serves_static:
+ # invert control to each plugin for finding their own static dirs
+ for plugin_url, plugin_static_path in framework.get_static_urls_and_paths():
+ plugin_url = '/plugins/' + plugin_url
+ urlmap[( plugin_url )] = Static( plugin_static_path, cache_time )
+ log.debug( 'added url, path to static middleware: %s, %s', plugin_url, plugin_static_path )
# URL mapper becomes the root webapp
return urlmap
diff -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 -r 2d0bcb07596c4c688ed3908391d866831c65c042 lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -698,10 +698,10 @@
registry = trans.app.visualizations_registry
if not registry:
raise HTTPNotFound( 'No visualization registry (possibly disabled in universe_wsgi.ini)' )
- if visualization_name not in registry.listings:
+ if visualization_name not in registry.plugins:
raise HTTPNotFound( 'Unknown or invalid visualization: ' + visualization_name )
# or redirect to list?
- registry_listing = registry.listings[ visualization_name ]
+ plugin = registry.plugins[ visualization_name ]
returned = None
try:
@@ -711,8 +711,8 @@
resources = registry.query_dict_to_resources( trans, self, visualization_name, kwargs )
# look up template and render
- template_path = registry_listing[ 'template' ]
- returned = registry.fill_template( trans, template_path,
+ template_path = plugin.config[ 'template' ]
+ returned = registry.fill_template( trans, plugin, template_path,
visualization_name=visualization_name, query_args=kwargs,
embedded=embedded, shared_vars={}, **resources )
#NOTE: passing *unparsed* kwargs as query_args
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Typo in toolshed util common.
by commits-noreply@bitbucket.org 17 Sep '13
by commits-noreply@bitbucket.org 17 Sep '13
17 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/b5c08cc6adbb/
Changeset: b5c08cc6adbb
User: dannon
Date: 2013-09-17 23:31:16
Summary: Typo in toolshed util common.
Affected #: 1 file
diff -r 1e664910d749be12d6f0ece29028f18b820476a1 -r b5c08cc6adbb64bb8dfa20070e6df5857483bd00 lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -1186,7 +1186,7 @@
encoded_tool_shed_status_dict = common_util.tool_shed_get( app, tool_shed_url, url )
tool_shed_status_dict = encoding_util.tool_shed_decode( encoded_tool_shed_status_dict )
except Exception, e:
- log.exception( "Error attemtping to get tool shed status for installed repository %s: %s" % ( str( repository.name ), str( e ) ) )
+ log.exception( "Error attempting to get tool shed status for installed repository %s: %s" % ( str( repository.name ), str( e ) ) )
return {}
return tool_shed_status_dict
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1c9adf19f128/
Changeset: 1c9adf19f128
User: mdshw5
Date: 2013-09-04 16:42:56
Summary: fixed it's > its typos
Affected #: 1 file
diff -r b9da077a79c3ce0323bd8f8e5aed3e311d1fd8ae -r 1c9adf19f12813b9802e84bbde73ca1e7758a498 templates/webapps/tool_shed/repository/common.mako
--- a/templates/webapps/tool_shed/repository/common.mako
+++ b/templates/webapps/tool_shed/repository/common.mako
@@ -1,4 +1,3 @@
-
<%def name="common_javascripts(repository)"><script type="text/javascript">
$(function(){
@@ -180,7 +179,7 @@
${repository_type | h}
%if render_help:
<div class="toolParamHelp" style="clear: both;">
- This repository's type cannot be changed because it's contents are valid only for it's current type or it has been cloned.
+ This repository's type cannot be changed because its contents are valid only for its current type or it has been cloned.
</div>
%endif
%else:
https://bitbucket.org/galaxy/galaxy-central/commits/1e664910d749/
Changeset: 1e664910d749
User: dannon
Date: 2013-09-17 22:46:32
Summary: Merged in mdshw5/galaxy-central-toolshed-typos (pull request #210)
fixed it's > its typos
Affected #: 1 file
diff -r 47798b37aed096b344c43c6796b7aae27ef11e90 -r 1e664910d749be12d6f0ece29028f18b820476a1 templates/webapps/tool_shed/repository/common.mako
--- a/templates/webapps/tool_shed/repository/common.mako
+++ b/templates/webapps/tool_shed/repository/common.mako
@@ -1,4 +1,3 @@
-
<%def name="common_javascripts(repository)"><script type="text/javascript">
$(function(){
@@ -180,7 +179,7 @@
${repository_type | h}
%if render_help:
<div class="toolParamHelp" style="clear: both;">
- This repository's type cannot be changed because it's contents are valid only for it's current type or it has been cloned.
+ This repository's type cannot be changed because its contents are valid only for its current type or it has been cloned.
</div>
%endif
%else:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/edc5e6ad3d54/
Changeset: edc5e6ad3d54
User: james_taylor
Date: 2013-09-11 22:24:44
Summary: style: use link color for active bg, update tooltip JS
Affected #: 5 files
diff -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b static/scripts/libs/bootstrap.js
--- a/static/scripts/libs/bootstrap.js
+++ b/static/scripts/libs/bootstrap.js
@@ -1,8 +1,63 @@
+/* ========================================================================
+ * Bootstrap: transition.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#transitions
+ * ========================================================================
+ * Copyright 2013 Twitter, Inc.
+ *
+ * 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.
+ * ======================================================================== */
-/* ===================================================
- * bootstrap-transition.js v2.0.4
- * http://twitter.github.com/bootstrap/javascript.html#transitions
- * ===================================================
+
++function ($) { "use strict";
+
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+ // ============================================================
+
+ function transitionEnd() {
+ var el = document.createElement('bootstrap')
+
+ var transEndEventNames = {
+ 'WebkitTransition' : 'webkitTransitionEnd'
+ , 'MozTransition' : 'transitionend'
+ , 'OTransition' : 'oTransitionEnd otransitionend'
+ , 'transition' : 'transitionend'
+ }
+
+ for (var name in transEndEventNames) {
+ if (el.style[name] !== undefined) {
+ return { end: transEndEventNames[name] }
+ }
+ }
+ }
+
+ // http://blog.alexmaccaw.com/css-transitions
+ $.fn.emulateTransitionEnd = function (duration) {
+ var called = false, $el = this
+ $(this).one($.support.transition.end, function () { called = true })
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+ setTimeout(callback, duration)
+ return this
+ }
+
+ $(function () {
+ $.support.transition = transitionEnd()
+ })
+
+}(window.jQuery);
+/* ========================================================================
+ * Bootstrap: tab.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#tabs
+ * ========================================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,55 +71,129 @@
* 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 ($) {
++function ($) { "use strict";
- $(function () {
+ // TAB CLASS DEFINITION
+ // ====================
- "use strict"; // jshint ;_;
+ var Tab = function (element) {
+ this.element = $(element)
+ }
+ Tab.prototype.show = function () {
+ var $this = this.element
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
+ var selector = $this.attr('data-target')
- /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
- * ======================================================= */
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
- $.support.transition = (function () {
+ if ($this.parent('li').hasClass('active')) return
- var transitionEnd = (function () {
+ var previous = $ul.find('.active:last a')[0]
+ var e = $.Event('show.bs.tab', {
+ relatedTarget: previous
+ })
- var el = document.createElement('bootstrap')
- , transEndEventNames = {
- 'WebkitTransition' : 'webkitTransitionEnd'
- , 'MozTransition' : 'transitionend'
- , 'OTransition' : 'oTransitionEnd'
- , 'msTransition' : 'MSTransitionEnd'
- , 'transition' : 'transitionend'
- }
- , name
+ $this.trigger(e)
- for (name in transEndEventNames){
- if (el.style[name] !== undefined) {
- return transEndEventNames[name]
- }
- }
+ if (e.isDefaultPrevented()) return
- }())
+ var $target = $(selector)
- return transitionEnd && {
- end: transitionEnd
+ this.activate($this.parent('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $this.trigger({
+ type: 'shown.bs.tab'
+ , relatedTarget: previous
+ })
+ })
+ }
+
+ Tab.prototype.activate = function (element, container, callback) {
+ var $active = container.find('> .active')
+ var transition = callback
+ && $.support.transition
+ && $active.hasClass('fade')
+
+ function next() {
+ $active
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+
+ element.addClass('active')
+
+ if (transition) {
+ element[0].offsetWidth // reflow for transition
+ element.addClass('in')
+ } else {
+ element.removeClass('fade')
}
- })()
+ if (element.parent('.dropdown-menu')) {
+ element.closest('li.dropdown').addClass('active')
+ }
+ callback && callback()
+ }
+
+ transition ?
+ $active
+ .one($.support.transition.end, next)
+ .emulateTransitionEnd(150) :
+ next()
+
+ $active.removeClass('in')
+ }
+
+
+ // TAB PLUGIN DEFINITION
+ // =====================
+
+ var old = $.fn.tab
+
+ $.fn.tab = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tab')
+
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tab.Constructor = Tab
+
+
+ // TAB NO CONFLICT
+ // ===============
+
+ $.fn.tab.noConflict = function () {
+ $.fn.tab = old
+ return this
+ }
+
+
+ // TAB DATA-API
+ // ============
+
+ $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+ e.preventDefault()
+ $(this).tab('show')
})
}(window.jQuery);
-
-/* ========================================================
- * bootstrap-tab.js v2.0.4
- * http://twitter.github.com/bootstrap/javascript.html#tabs
- * ========================================================
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -78,452 +207,371 @@
* 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 ($) {
++function ($) { "use strict";
- "use strict"; // jshint ;_;
+ // TOOLTIP PUBLIC CLASS DEFINITION
+ // ===============================
+ var Tooltip = function (element, options) {
+ this.type =
+ this.options =
+ this.enabled =
+ this.timeout =
+ this.hoverState =
+ this.$element = null
- /* TAB CLASS DEFINITION
- * ==================== */
-
- var Tab = function ( element ) {
- this.element = $(element)
+ this.init('tooltip', element, options)
}
- Tab.prototype = {
+ Tooltip.DEFAULTS = {
+ animation: true
+ , placement: 'top'
+ , selector: false
+ , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
+ , trigger: 'hover focus'
+ , title: ''
+ , delay: 0
+ , html: false
+ , container: 'body'
+ }
- constructor: Tab
+ Tooltip.prototype.init = function (type, element, options) {
+ this.enabled = true
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
- , show: function () {
- var $this = this.element
- , $ul = $this.closest('ul:not(.dropdown-menu)')
- , selector = $this.attr('data-target')
- , previous
- , $target
- , e
+ var triggers = this.options.trigger.split(' ')
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ for (var i = triggers.length; i--;) {
+ var trigger = triggers[i]
+
+ if (trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
+
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
}
+ }
- if ( $this.parent('li').hasClass('active') ) return
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
- previous = $ul.find('.active a').last()[0]
+ Tooltip.prototype.getDefaults = function () {
+ return Tooltip.DEFAULTS
+ }
- e = $.Event('show', {
- relatedTarget: previous
- })
+ Tooltip.prototype.getOptions = function (options) {
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
- $this.trigger(e)
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay
+ , hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ Tooltip.prototype.getDelegateOptions = function () {
+ var options = {}
+ var defaults = this.getDefaults()
+
+ this._options && $.each(this._options, function (key, value) {
+ if (defaults[key] != value) options[key] = value
+ })
+
+ return options
+ }
+
+ Tooltip.prototype.enter = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'in'
+
+ if (!self.options.delay || !self.options.delay.show) return self.show()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'in') self.show()
+ }, self.options.delay.show)
+ }
+
+ Tooltip.prototype.leave = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'out'
+
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'out') self.hide()
+ }, self.options.delay.hide)
+ }
+
+ Tooltip.prototype.show = function () {
+ var e = $.Event('show.bs.'+ this.type)
+
+ if (this.hasContent() && this.enabled) {
+ this.$element.trigger(e)
if (e.isDefaultPrevented()) return
- $target = $(selector)
+ var $tip = this.tip()
- this.activate($this.parent('li'), $ul)
- this.activate($target, $target.parent(), function () {
- $this.trigger({
- type: 'shown'
- , relatedTarget: previous
- })
- })
- }
+ this.setContent()
- , activate: function ( element, container, callback) {
- var $active = container.find('> .active')
- , transition = callback
- && $.support.transition
- && $active.hasClass('fade')
+ if (this.options.animation) $tip.addClass('fade')
- function next() {
- $active
- .removeClass('active')
- .find('> .dropdown-menu > .active')
- .removeClass('active')
+ var placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
- element.addClass('active')
+ var autoToken = /\s?auto?\s?/i
+ var autoPlace = autoToken.test(placement)
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
- if (transition) {
- element[0].offsetWidth // reflow for transition
- element.addClass('in')
- } else {
- element.removeClass('fade')
- }
+ $tip
+ .detach()
+ .css({ top: 0, left: 0, display: 'block' })
+ .addClass(placement)
- if ( element.parent('.dropdown-menu') ) {
- element.closest('li.dropdown').addClass('active')
- }
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
- callback && callback()
+ var pos = this.getPosition()
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (autoPlace) {
+ var $parent = this.$element.parent()
+
+ var orgPlacement = placement
+ var docScroll = document.documentElement.scrollTop || document.body.scrollTop
+ var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth()
+ var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
+ var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left
+
+ placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' :
+ placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' :
+ placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' :
+ placement
+
+ $tip
+ .removeClass(orgPlacement)
+ .addClass(placement)
}
- transition ?
- $active.one($.support.transition.end, next) :
- next()
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
- $active.removeClass('in')
+ this.applyPlacement(calculatedOffset, placement)
+ this.$element.trigger('shown.bs.' + this.type)
}
}
+ Tooltip.prototype.applyPlacement = function(offset, placement) {
+ var replace
+ var $tip = this.tip()
+ var width = $tip[0].offsetWidth
+ var height = $tip[0].offsetHeight
- /* TAB PLUGIN DEFINITION
- * ===================== */
+ // manually read margins because getBoundingClientRect includes difference
+ var marginTop = parseInt($tip.css('margin-top'), 10)
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
- $.fn.tab = function ( option ) {
- return this.each(function () {
- var $this = $(this)
- , data = $this.data('tab')
- if (!data) $this.data('tab', (data = new Tab(this)))
- if (typeof option == 'string') data[option]()
- })
+ // we must check for NaN for ie 8/9
+ if (isNaN(marginTop)) marginTop = 0
+ if (isNaN(marginLeft)) marginLeft = 0
+
+ offset.top = offset.top + marginTop
+ offset.left = offset.left + marginLeft
+
+ $tip
+ .offset(offset)
+ .addClass('in')
+
+ // check to see if placing tip in new offset caused the tip to resize itself
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (placement == 'top' && actualHeight != height) {
+ replace = true
+ offset.top = offset.top + height - actualHeight
+ }
+
+ if (/bottom|top/.test(placement)) {
+ var delta = 0
+
+ if (offset.left < 0) {
+ delta = offset.left * -2
+ offset.left = 0
+
+ $tip.offset(offset)
+
+ actualWidth = $tip[0].offsetWidth
+ actualHeight = $tip[0].offsetHeight
+ }
+
+ this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+ } else {
+ this.replaceArrow(actualHeight - height, actualHeight, 'top')
+ }
+
+ if (replace) $tip.offset(offset)
}
- $.fn.tab.Constructor = Tab
-
-
- /* TAB DATA-API
- * ============ */
-
- $(function () {
- $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
- e.preventDefault()
- $(this).tab('show')
- })
- })
-
-}(window.jQuery);
-
-/* ===========================================================
- * bootstrap-tooltip.js v2.0.4
- * http://twitter.github.com/bootstrap/javascript.html#tooltips
- * Inspired by the original jQuery.tipsy by Jason Frame
- * ===========================================================
- * Copyright 2012 Twitter, Inc.
- *
- * 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 ($) {
-
- "use strict"; // jshint ;_;
-
- // Add a special event that is called when an element is destroyed
- (function($){
- jQuery.event.special.destroyed = {
- remove: function(o) {
- if (o.handler) {
- o.handler()
- }
- }
- }
- })(jQuery)
-
- /* TOOLTIP PUBLIC CLASS DEFINITION
- * =============================== */
-
- var Tooltip = function (element, options) {
- this.init('tooltip', element, options)
+ Tooltip.prototype.replaceArrow = function(delta, dimension, position) {
+ this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
}
- Tooltip.prototype = {
+ Tooltip.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
- constructor: Tooltip
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+ $tip.removeClass('fade in top bottom left right')
+ }
- , init: function (type, element, options) {
- var eventIn
- , eventOut
+ Tooltip.prototype.hide = function () {
+ var that = this
+ var $tip = this.tip()
+ var e = $.Event('hide.bs.' + this.type)
- this.type = type
- this.$element = $(element)
- this.options = this.getOptions(options)
- this.enabled = true
-
- if (this.options.trigger != 'manual') {
- eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
- eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
- this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
- this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
- }
-
- // Make sure tooltip is hidden when element is destroyed
- this.$element.on( 'destroyed', $.proxy( this.hide, this ) );
-
- this.options.selector ?
- (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
- this.fixTitle()
+ function complete() {
+ if (that.hoverState != 'in') $tip.detach()
}
- , getOptions: function (options) {
- options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
+ this.$element.trigger(e)
- if (options.delay && typeof options.delay == 'number') {
- options.delay = {
- show: options.delay
- , hide: options.delay
- }
- }
+ if (e.isDefaultPrevented()) return
- return options
- }
+ $tip.removeClass('in')
- , enter: function (e) {
- var self = $(e.currentTarget)[this.type](this._options).data(this.type)
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one($.support.transition.end, complete)
+ .emulateTransitionEnd(150) :
+ complete()
- if (!self.options.delay || !self.options.delay.show) return self.show()
+ this.$element.trigger('hidden.bs.' + this.type)
- clearTimeout(this.timeout)
- self.hoverState = 'in'
- this.timeout = setTimeout(function() {
- if (self.hoverState == 'in') self.show()
- }, self.options.delay.show)
- }
-
- , leave: function (e) {
- var self = $(e.currentTarget)[this.type](this._options).data(this.type)
-
- if (this.timeout) clearTimeout(this.timeout)
- if (!self.options.delay || !self.options.delay.hide) return self.hide()
-
- self.hoverState = 'out'
- this.timeout = setTimeout(function() {
- if (self.hoverState == 'out') self.hide()
- }, self.options.delay.hide)
- }
-
- , show: function () {
- var $tip
- , inside
- , pos
- , actualWidth
- , actualHeight
- , placement
- , placementPosition
- , $window
- , tp
-
- if (this.hasContent() && this.enabled) {
- $tip = this.tip()
- this.setContent()
-
- if (this.options.animation) {
- $tip.addClass('fade')
- }
-
- placement = typeof this.options.placement == 'function' ?
- this.options.placement.call(this, $tip[0], this.$element[0]) :
- this.options.placement
-
- placementPosition = inside ? placement.split(' ')[1] : placement;
-
- inside = /in/.test(placement)
-
- $tip
- .remove()
- .css({ top: 0, left: 0, display: 'block' })
- .appendTo(inside ? this.$element : document.body)
-
- pos = this.getPosition(inside)
-
- actualWidth = $tip[0].offsetWidth
- actualHeight = $tip[0].offsetHeight
-
- switch (placementPosition) {
- case 'bottom':
- tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
- break
- case 'top':
- tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
- break
- case 'left':
- tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
- break
- case 'right':
- tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
- break
- }
-
- // Shift if off screen
- $window = $(window)
-
- // If off the top of the screen, flip
- if ( tp.top < $window.scrollTop() && placementPosition == 'top' ) {
- tp.top = pos.top + pos.height;
- placement = inside ? 'inside bottom' : 'bottom';
- }
-
- // Shift left or right
- var leftShift = 0;
- if ( tp.left < $window.scrollLeft() ) {
- leftShift = tp.left - $window.scrollLeft();
- }
- var t = $window.scrollLeft() + $window.width() - $tip.outerWidth();
- if ( tp.left > t ) {
- leftShift = tp.left - t;
- }
-
- tp.left -= leftShift;
-
- // Shift background to center over element (not implemented for east/west)
- switch (inside ? placement.split(' ')[1] : placement) {
- case 'bottom':
- $tip.find('.tooltip-arrow').css( 'left', ( $tip.outerWidth() / 2 ) + leftShift + "px" );
- break;
- case 'top':
- $tip.find('.tooltip-arrow').css( 'left', ( $tip.outerWidth() / 2 ) + leftShift + "px" );
- break;
- case 'left':
- break;
- case 'right':
- break;
- }
-
- // END GALAXY MODIFICATION
-
-
- $tip
- .css(tp)
- .addClass(placement)
- .addClass('in')
- }
- }
-
- , isHTML: function(text) {
- // html string detection logic adapted from jQuery
- return typeof text != 'string'
- || ( text.charAt(0) === "<"
- && text.charAt( text.length - 1 ) === ">"
- && text.length >= 3
- ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
- }
-
- , setContent: function () {
- var $tip = this.tip()
- , title = this.getTitle()
-
- $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
- $tip.removeClass('fade in top bottom left right')
- }
-
- , hide: function () {
- var that = this
- , $tip = this.tip()
-
- $tip.removeClass('in')
-
- function removeWithAnimation() {
- var timeout = setTimeout(function () {
- $tip.off($.support.transition.end).remove()
- }, 500)
-
- $tip.one($.support.transition.end, function () {
- clearTimeout(timeout)
- $tip.remove()
- })
- }
-
- $.support.transition && this.$tip.hasClass('fade') ?
- removeWithAnimation() :
- $tip.remove()
- }
-
- , fixTitle: function () {
- var $e = this.$element
- if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
- $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
- }
- }
-
- , hasContent: function () {
- return this.getTitle()
- }
-
- , getPosition: function (inside) {
- return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
- width: this.$element[0].offsetWidth
- , height: this.$element[0].offsetHeight
- })
- }
-
- , getTitle: function () {
- var title
- , $e = this.$element
- , o = this.options
-
- title = $e.attr('data-original-title')
- || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
-
- return title
- }
-
- , tip: function () {
- return this.$tip = this.$tip || $(this.options.template)
- }
-
- , validate: function () {
- if (!this.$element[0].parentNode) {
- this.hide()
- this.$element = null
- this.options = null
- }
- }
-
- , enable: function () {
- this.enabled = true
- }
-
- , disable: function () {
- this.enabled = false
- }
-
- , toggleEnabled: function () {
- this.enabled = !this.enabled
- }
-
- , toggle: function () {
- this[this.tip().hasClass('in') ? 'hide' : 'show']()
- }
-
+ return this
}
+ Tooltip.prototype.fixTitle = function () {
+ var $e = this.$element
+ if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+ }
+ }
- /* TOOLTIP PLUGIN DEFINITION
- * ========================= */
+ Tooltip.prototype.hasContent = function () {
+ return this.getTitle()
+ }
- $.fn.tooltip = function ( option ) {
+ Tooltip.prototype.getPosition = function () {
+ var el = this.$element[0]
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+ width: el.offsetWidth
+ , height: el.offsetHeight
+ }, this.$element.offset())
+ }
+
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+ }
+
+ Tooltip.prototype.getTitle = function () {
+ var title
+ var $e = this.$element
+ var o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ return title
+ }
+
+ Tooltip.prototype.tip = function () {
+ return this.$tip = this.$tip || $(this.options.template)
+ }
+
+ Tooltip.prototype.arrow = function () {
+ return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
+ }
+
+ Tooltip.prototype.validate = function () {
+ if (!this.$element[0].parentNode) {
+ this.hide()
+ this.$element = null
+ this.options = null
+ }
+ }
+
+ Tooltip.prototype.enable = function () {
+ this.enabled = true
+ }
+
+ Tooltip.prototype.disable = function () {
+ this.enabled = false
+ }
+
+ Tooltip.prototype.toggleEnabled = function () {
+ this.enabled = !this.enabled
+ }
+
+ Tooltip.prototype.toggle = function (e) {
+ var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+ }
+
+ Tooltip.prototype.destroy = function () {
+ this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+ }
+
+
+ // TOOLTIP PLUGIN DEFINITION
+ // =========================
+
+ var old = $.fn.tooltip
+
+ $.fn.tooltip = function (option) {
return this.each(function () {
- var $this = $(this)
- , data = $this.data('tooltip')
- , options = typeof option == 'object' && option
- if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
+ var $this = $(this)
+ var data = $this.data('bs.tooltip')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.tooltip.Constructor = Tooltip
- $.fn.tooltip.defaults = {
- animation: false
- , placement: 'top'
- , selector: false
- , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
- , trigger: 'hover'
- , title: ''
- , delay: 0
+
+ // TOOLTIP NO CONFLICT
+ // ===================
+
+ $.fn.tooltip.noConflict = function () {
+ $.fn.tooltip = old
+ return this
}
}(window.jQuery);
diff -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b static/scripts/packed/galaxy.modal.js
--- a/static/scripts/packed/galaxy.modal.js
+++ b/static/scripts/packed/galaxy.modal.js
@@ -1,1 +1,1 @@
-define(["libs/backbone/backbone-relational"],function(){var a=Backbone.View.extend({el_main:"#everything",options:{title:"galaxy-modal",body:"No content available."},initialize:function(b){if(b){this.create(b);$(this.el).hide()}},show:function(b){if(b){this.create(b)}this.$el.fadeIn("fast")},hide:function(){this.$el.fadeOut("fast")},create:function(c){this.$el.remove();if(!c){c=this.options}else{c=_.defaults(c,this.options)}this.setElement(this.template(c.title,c.body));$(this.el_main).append($(this.el));var d=(this.$el).find(".footer");var b=this;if(c.buttons){$.each(c.buttons,function(e,f){d.append($("<button></button>").text(e).click(f)).append(" ")})}else{d.append($("<button></button>").text("Close").click(function(){b.hide()})).append(" ")}},template:function(c,b){return'<div class="modal"><div class="modal-backdrop"></div><div class="modal-dialog galaxy-corner"><div class="modal-content"><div class="header"><span><h3 class="title">'+c+'</h3></span></div><div class="body">'+b+'</div><div class="footer"></div></div</div></div>'}});return{GalaxyModal:a}});
\ No newline at end of file
+define(["libs/backbone/backbone-relational"],function(){var a=Backbone.View.extend({el_main:"#everything",options:{title:"galaxy-modal",body:"No content available."},initialize:function(b){if(b){this.create(b);$(this.el).hide()}},show:function(b){if(b){this.create(b)}this.$el.fadeIn("fast")},hide:function(){this.$el.fadeOut("fast")},create:function(c){this.$el.remove();if(!c){c=this.options}else{c=_.defaults(c,this.options)}this.setElement(this.template(c.title,c.body));$(this.el_main).append($(this.el));var d=(this.$el).find(".buttons");var b=this;if(c.buttons){$.each(c.buttons,function(e,f){d.append($("<button></button>").text(e).click(f)).append(" ")})}else{d.append($("<button></button>").text("Close").click(function(){b.hide()})).append(" ")}},template:function(c,b){return'<div class="modal in"><div class="modal-backdrop in" style="z-index: -1;"></div><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><span><h3 class="title">'+c+'</h3></span></div><div class="modal-body style="min-width: 540px; max-height: 445px;">'+b+'</div><div class="modal-footer"><div class="buttons" style="float: right;"></div></div></div</div></div>'}});return{GalaxyModal:a}});
\ No newline at end of file
diff -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b static/scripts/packed/libs/bootstrap.js
--- a/static/scripts/packed/libs/bootstrap.js
+++ b/static/scripts/packed/libs/bootstrap.js
@@ -1,1 +1,1 @@
-!function(a){a(function(){a.support.transition=(function(){var b=(function(){var e=document.createElement("bootstrap"),d={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},c;for(c in d){if(e.style[c]!==undefined){return d[c]}}}());return b&&{end:b}})()})}(window.jQuery);!function(b){var a=function(c){this.element=b(c)};a.prototype={constructor:a,show:function(){var i=this.element,f=i.closest("ul:not(.dropdown-menu)"),d=i.attr("data-target"),g,c,h;if(!d){d=i.attr("href");d=d&&d.replace(/.*(?=#[^\s]*$)/,"")}if(i.parent("li").hasClass("active")){return}g=f.find(".active a").last()[0];h=b.Event("show",{relatedTarget:g});i.trigger(h);if(h.isDefaultPrevented()){return}c=b(d);this.activate(i.parent("li"),f);this.activate(c,c.parent(),function(){i.trigger({type:"shown",relatedTarget:g})})},activate:function(e,d,h){var c=d.find("> .active"),g=h&&b.support.transition&&c.hasClass("fade");function f(){c.removeClass("active").find("> .dropdown-menu > .active").removeClass("active");e.addClass("active");if(g){e[0].offsetWidth;e.addClass("in")}else{e.removeClass("fade")}if(e.parent(".dropdown-menu")){e.closest("li.dropdown").addClass("active")}h&&h()}g?c.one(b.support.transition.end,f):f();c.removeClass("in")}};b.fn.tab=function(c){return this.each(function(){var e=b(this),d=e.data("tab");if(!d){e.data("tab",(d=new a(this)))}if(typeof c=="string"){d[c]()}})};b.fn.tab.Constructor=a;b(function(){b("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(c){c.preventDefault();b(this).tab("show")})})}(window.jQuery);!function(b){(function(c){jQuery.event.special.destroyed={remove:function(d){if(d.handler){d.handler()}}}})(jQuery);var a=function(d,c){this.init("tooltip",d,c)};a.prototype={constructor:a,init:function(f,e,d){var g,c;this.type=f;this.$element=b(e);this.options=this.getOptions(d);this.enabled=true;if(this.options.trigger!="manual"){g=this.options.trigger=="hover"?"mouseenter":"focus";c=this.options.trigger=="hover"?"mouseleave":"blur";this.$element.on(g,this.options.selector,b.proxy(this.enter,this));this.$element.on(c,this.options.selector,b.proxy(this.leave,this))}this.$element.on("destroyed",b.proxy(this.hide,this));this.options.selector?(this._options=b.extend({},this.options,{trigger:"manual",selector:""})):this.fixTitle()},getOptions:function(c){c=b.extend({},b.fn[this.type].defaults,c,this.$element.data());if(c.delay&&typeof c.delay=="number"){c.delay={show:c.delay,hide:c.delay}}return c},enter:function(d){var c=b(d.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.show){return c.show()}clearTimeout(this.timeout);c.hoverState="in";this.timeout=setTimeout(function(){if(c.hoverState=="in"){c.show()}},c.options.delay.show)},leave:function(d){var c=b(d.currentTarget)[this.type](this._options).data(this.type);if(this.timeout){clearTimeout(this.timeout)}if(!c.options.delay||!c.options.delay.hide){return c.hide()}c.hoverState="out";this.timeout=setTimeout(function(){if(c.hoverState=="out"){c.hide()}},c.options.delay.hide)},show:function(){var i,f,k,c,j,h,e,d,l;if(this.hasContent()&&this.enabled){i=this.tip();this.setContent();if(this.options.animation){i.addClass("fade")}h=typeof this.options.placement=="function"?this.options.placement.call(this,i[0],this.$element[0]):this.options.placement;e=f?h.split(" ")[1]:h;f=/in/.test(h);i.remove().css({top:0,left:0,display:"block"}).appendTo(f?this.$element:document.body);k=this.getPosition(f);c=i[0].offsetWidth;j=i[0].offsetHeight;switch(e){case"bottom":l={top:k.top+k.height,left:k.left+k.width/2-c/2};break;case"top":l={top:k.top-j,left:k.left+k.width/2-c/2};break;case"left":l={top:k.top+k.height/2-j/2,left:k.left-c};break;case"right":l={top:k.top+k.height/2-j/2,left:k.left+k.width};break}d=b(window);if(l.top<d.scrollTop()&&e=="top"){l.top=k.top+k.height;h=f?"inside bottom":"bottom"}var g=0;if(l.left<d.scrollLeft()){g=l.left-d.scrollLeft()}var m=d.scrollLeft()+d.width()-i.outerWidth();if(l.left>m){g=l.left-m}l.left-=g;switch(f?h.split(" ")[1]:h){case"bottom":i.find(".tooltip-arrow").css("left",(i.outerWidth()/2)+g+"px");break;case"top":i.find(".tooltip-arrow").css("left",(i.outerWidth()/2)+g+"px");break;case"left":break;case"right":break}i.css(l).addClass(h).addClass("in")}},isHTML:function(c){return typeof c!="string"||(c.charAt(0)==="<"&&c.charAt(c.length-1)===">"&&c.length>=3)||/^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(c)},setContent:function(){var d=this.tip(),c=this.getTitle();d.find(".tooltip-inner")[this.isHTML(c)?"html":"text"](c);d.removeClass("fade in top bottom left right")},hide:function(){var c=this,d=this.tip();d.removeClass("in");function e(){var f=setTimeout(function(){d.off(b.support.transition.end).remove()},500);d.one(b.support.transition.end,function(){clearTimeout(f);d.remove()})}b.support.transition&&this.$tip.hasClass("fade")?e():d.remove()},fixTitle:function(){var c=this.$element;if(c.attr("title")||typeof(c.attr("data-original-title"))!="string"){c.attr("data-original-title",c.attr("title")||"").removeAttr("title")}},hasContent:function(){return this.getTitle()},getPosition:function(c){return b.extend({},(c?{top:0,left:0}:this.$element.offset()),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var e,c=this.$element,d=this.options;e=c.attr("data-original-title")||(typeof d.title=="function"?d.title.call(c[0]):d.title);return e},tip:function(){return this.$tip=this.$tip||b(this.options.template)},validate:function(){if(!this.$element[0].parentNode){this.hide();this.$element=null;this.options=null}},enable:function(){this.enabled=true},disable:function(){this.enabled=false},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()}};b.fn.tooltip=function(c){return this.each(function(){var f=b(this),e=f.data("tooltip"),d=typeof c=="object"&&c;if(!e){f.data("tooltip",(e=new a(this,d)))}if(typeof c=="string"){e[c]()}})};b.fn.tooltip.Constructor=a;b.fn.tooltip.defaults={animation:false,placement:"top",selector:false,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover",title:"",delay:0}}(window.jQuery);
\ No newline at end of file
++function(b){function a(){var e=document.createElement("bootstrap");var d={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in d){if(e.style[c]!==undefined){return{end:d[c]}}}}b.fn.emulateTransitionEnd=function(e){var d=false,c=this;b(this).one(b.support.transition.end,function(){d=true});var f=function(){if(!d){b(c).trigger(b.support.transition.end)}};setTimeout(f,e);return this};b(function(){b.support.transition=a()})}(window.jQuery);+function(c){var b=function(d){this.element=c(d)};b.prototype.show=function(){var j=this.element;var g=j.closest("ul:not(.dropdown-menu)");var f=j.attr("data-target");if(!f){f=j.attr("href");f=f&&f.replace(/.*(?=#[^\s]*$)/,"")}if(j.parent("li").hasClass("active")){return}var h=g.find(".active:last a")[0];var i=c.Event("show.bs.tab",{relatedTarget:h});j.trigger(i);if(i.isDefaultPrevented()){return}var d=c(f);this.activate(j.parent("li"),g);this.activate(d,d.parent(),function(){j.trigger({type:"shown.bs.tab",relatedTarget:h})})};b.prototype.activate=function(f,e,i){var d=e.find("> .active");var h=i&&c.support.transition&&d.hasClass("fade");function g(){d.removeClass("active").find("> .dropdown-menu > .active").removeClass("active");f.addClass("active");if(h){f[0].offsetWidth;f.addClass("in")}else{f.removeClass("fade")}if(f.parent(".dropdown-menu")){f.closest("li.dropdown").addClass("active")}i&&i()}h?d.one(c.support.transition.end,g).emulateTransitionEnd(150):g();d.removeClass("in")};var a=c.fn.tab;c.fn.tab=function(d){return this.each(function(){var f=c(this);var e=f.data("bs.tab");if(!e){f.data("bs.tab",(e=new b(this)))}if(typeof d=="string"){e[d]()}})};c.fn.tab.Constructor=b;c.fn.tab.noConflict=function(){c.fn.tab=a;return this};c(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(d){d.preventDefault();c(this).tab("show")})}(window.jQuery);+function(c){var b=function(e,d){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null;this.init("tooltip",e,d)};b.DEFAULTS={animation:true,placement:"top",selector:false,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:false,container:"body"};b.prototype.init=function(k,h,f){this.enabled=true;this.type=k;this.$element=c(h);this.options=this.getOptions(f);var j=this.options.trigger.split(" ");for(var g=j.length;g--;){var e=j[g];if(e=="click"){this.$element.on("click."+this.type,this.options.selector,c.proxy(this.toggle,this))}else{if(e!="manual"){var l=e=="hover"?"mouseenter":"focus";var d=e=="hover"?"mouseleave":"blur";this.$element.on(l+"."+this.type,this.options.selector,c.proxy(this.enter,this));this.$element.on(d+"."+this.type,this.options.selector,c.proxy(this.leave,this))}}}this.options.selector?(this._options=c.extend({},this.options,{trigger:"manual",selector:""})):this.fixTitle()};b.prototype.getDefaults=function(){return b.DEFAULTS};b.prototype.getOptions=function(d){d=c.extend({},this.getDefaults(),this.$element.data(),d);if(d.delay&&typeof d.delay=="number"){d.delay={show:d.delay,hide:d.delay}}return d};b.prototype.getDelegateOptions=function(){var d={};var e=this.getDefaults();this._options&&c.each(this._options,function(f,g){if(e[f]!=g){d[f]=g}});return d};b.prototype.enter=function(e){var d=e instanceof this.constructor?e:c(e.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);clearTimeout(d.timeout);d.hoverState="in";if(!d.options.delay||!d.options.delay.show){return d.show()}d.timeout=setTimeout(function(){if(d.hoverState=="in"){d.show()}},d.options.delay.show)};b.prototype.leave=function(e){var d=e instanceof this.constructor?e:c(e.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);clearTimeout(d.timeout);d.hoverState="out";if(!d.options.delay||!d.options.delay.hide){return d.hide()}d.timeout=setTimeout(function(){if(d.hoverState=="out"){d.hide()}},d.options.delay.hide)};b.prototype.show=function(){var n=c.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(n);if(n.isDefaultPrevented()){return}var j=this.tip();this.setContent();if(this.options.animation){j.addClass("fade")}var i=typeof this.options.placement=="function"?this.options.placement.call(this,j[0],this.$element[0]):this.options.placement;var r=/\s?auto?\s?/i;var s=r.test(i);if(s){i=i.replace(r,"")||"top"}j.detach().css({top:0,left:0,display:"block"}).addClass(i);this.options.container?j.appendTo(this.options.container):j.insertAfter(this.$element);var o=this.getPosition();var d=j[0].offsetWidth;var l=j[0].offsetHeight;if(s){var h=this.$element.parent();var g=i;var p=document.documentElement.scrollTop||document.body.scrollTop;var q=this.options.container=="body"?window.innerWidth:h.outerWidth();var m=this.options.container=="body"?window.innerHeight:h.outerHeight();var k=this.options.container=="body"?0:h.offset().left;i=i=="bottom"&&o.top+o.height+l-p>m?"top":i=="top"&&o.top-p-l<0?"bottom":i=="right"&&o.right+d>q?"left":i=="left"&&o.left-d<k?"right":i;j.removeClass(g).addClass(i)}var f=this.getCalculatedOffset(i,o,d,l);this.applyPlacement(f,i);this.$element.trigger("shown.bs."+this.type)}};b.prototype.applyPlacement=function(i,j){var g;var k=this.tip();var f=k[0].offsetWidth;var n=k[0].offsetHeight;var e=parseInt(k.css("margin-top"),10);var h=parseInt(k.css("margin-left"),10);if(isNaN(e)){e=0}if(isNaN(h)){h=0}i.top=i.top+e;i.left=i.left+h;k.offset(i).addClass("in");var d=k[0].offsetWidth;var l=k[0].offsetHeight;if(j=="top"&&l!=n){g=true;i.top=i.top+n-l}if(/bottom|top/.test(j)){var m=0;if(i.left<0){m=i.left*-2;i.left=0;k.offset(i);d=k[0].offsetWidth;l=k[0].offsetHeight}this.replaceArrow(m-f+d,d,"left")}else{this.replaceArrow(l-n,l,"top")}if(g){k.offset(i)}};b.prototype.replaceArrow=function(f,e,d){this.arrow().css(d,f?(50*(1-f/e)+"%"):"")};b.prototype.setContent=function(){var e=this.tip();var d=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](d);e.removeClass("fade in top bottom left right")};b.prototype.hide=function(){var f=this;var h=this.tip();var g=c.Event("hide.bs."+this.type);function d(){if(f.hoverState!="in"){h.detach()}}this.$element.trigger(g);if(g.isDefaultPrevented()){return}h.removeClass("in");c.support.transition&&this.$tip.hasClass("fade")?h.one(c.support.transition.end,d).emulateTransitionEnd(150):d();this.$element.trigger("hidden.bs."+this.type);return this};b.prototype.fixTitle=function(){var d=this.$element;if(d.attr("title")||typeof(d.attr("data-original-title"))!="string"){d.attr("data-original-title",d.attr("title")||"").attr("title","")}};b.prototype.hasContent=function(){return this.getTitle()};b.prototype.getPosition=function(){var d=this.$element[0];return c.extend({},(typeof d.getBoundingClientRect=="function")?d.getBoundingClientRect():{width:d.offsetWidth,height:d.offsetHeight},this.$element.offset())};b.prototype.getCalculatedOffset=function(d,g,e,f){return d=="bottom"?{top:g.top+g.height,left:g.left+g.width/2-e/2}:d=="top"?{top:g.top-f,left:g.left+g.width/2-e/2}:d=="left"?{top:g.top+g.height/2-f/2,left:g.left-e}:{top:g.top+g.height/2-f/2,left:g.left+g.width}};b.prototype.getTitle=function(){var f;var d=this.$element;var e=this.options;f=d.attr("data-original-title")||(typeof e.title=="function"?e.title.call(d[0]):e.title);return f};b.prototype.tip=function(){return this.$tip=this.$tip||c(this.options.template)};b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")};b.prototype.validate=function(){if(!this.$element[0].parentNode){this.hide();this.$element=null;this.options=null}};b.prototype.enable=function(){this.enabled=true};b.prototype.disable=function(){this.enabled=false};b.prototype.toggleEnabled=function(){this.enabled=!this.enabled};b.prototype.toggle=function(f){var d=f?c(f.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;d.tip().hasClass("in")?d.leave(d):d.enter(d)};b.prototype.destroy=function(){this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var a=c.fn.tooltip;c.fn.tooltip=function(d){return this.each(function(){var g=c(this);var f=g.data("bs.tooltip");var e=typeof d=="object"&&d;if(!f){g.data("bs.tooltip",(f=new b(this,e)))}if(typeof d=="string"){f[d]()}})};c.fn.tooltip.Constructor=b;c.fn.tooltip.noConflict=function(){c.fn.tooltip=a;return this}}(window.jQuery);
\ No newline at end of file
diff -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -422,8 +422,8 @@
.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:12px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:3px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}
.dropdown-menu .divider{height:1px;margin:7.5px 0;overflow:hidden;background-color:#e5e5e5}
.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}
-.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#fff;background-color:#00f}
-.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#00f}
+.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#fff;background-color:#303030}
+.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#303030}
.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}
.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}
.open>.dropdown-menu{display:block}
@@ -513,7 +513,7 @@
@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:3px 3px 0 0} .nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}
.nav-pills>li{float:left}.nav-pills>li>a{border-radius:5px}
.nav-pills>li+li{margin-left:2px}
-.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#00f}
+.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#303030}
.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}
.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}
@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}
@@ -659,8 +659,8 @@
.list-group-item>.badge+.badge{margin-right:5px}
a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}
a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}
-.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#00f;border-color:#00f}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading{color:inherit}
-.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#ccf}
+.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#303030;border-color:#303030}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading{color:inherit}
+.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#969696}
.list-group-item-heading{margin-top:0;margin-bottom:5px}
.list-group-item-text{margin-bottom:0;line-height:1.3}
.panel{margin-bottom:17px;background-color:#fff;border:1px solid transparent;border-radius:3px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}
diff -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b static/style/src/less/theme/blue.less
--- a/static/style/src/less/theme/blue.less
+++ b/static/style/src/less/theme/blue.less
@@ -11,6 +11,7 @@
@table-border-color: darken(@table-heading-bg,20%);
@link-color: #303030;
+@component-active-bg: @link-color;
@brand-primary: blue;
https://bitbucket.org/galaxy/galaxy-central/commits/47798b37aed0/
Changeset: 47798b37aed0
User: james_taylor
Date: 2013-09-17 21:18:51
Summary: Fix close/delete icons in workflow editor.
Affected #: 3 files
diff -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b -r 47798b37aed096b344c43c6796b7aae27ef11e90 static/scripts/galaxy.workflow_editor.canvas.js
--- a/static/scripts/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/galaxy.workflow_editor.canvas.js
@@ -199,8 +199,8 @@
.css( { display: 'none' } )
.appendTo( "body" )
.append(
- $("<div class='buttons'></div>").append(
- $("<img/>").attr("src", galaxy_config.root + 'static/images/delete_icon.png').click( function() {
+ $("<div class='button'></div>").append(
+ $("<div/>").addClass("fa-icon-button fa-icon-remove").click( function() {
$.each( terminal.connectors, function( _, x ) {
if (x) {
x.destroy();
@@ -859,12 +859,9 @@
// Fix width to computed width
// Now add floats
var buttons = $("<div class='buttons' style='float: right;'></div>");
- buttons.append( $("<img/>").attr("src", galaxy_config.root + 'static/images/delete_icon.png').click( function( e ) {
+ buttons.append( $("<div>").addClass("fa-icon-button fa-icon-remove").click( function( e ) {
node.destroy();
- } ).hover(
- function() { $(this).attr( "src", galaxy_config.root + "static/images/delete_icon_dark.png" ); },
- function() { $(this).attr( "src", galaxy_config.root + "static/images/delete_icon.png" ); }
- ) );
+ }));
// Place inside container
f.appendTo( "#canvas-container" );
// Position in container
diff -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b -r 47798b37aed096b344c43c6796b7aae27ef11e90 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1362,6 +1362,7 @@
.text-content th,.text-content td{border-bottom:1px solid #ddd;border-right:1px solid #ccc}
.text-content th,.text-content td{padding:.8em}
.icon-button{width:16px;height:16px;display:block;float:left;margin-left:2px;text-indent:20px;background-repeat:no-repeat;background-position:0px 0px;padding:0}
+.fa-icon-button{text-align:center;text-decoration:none;display:inline-block;cursor:pointer;width:16px;height:16px;line-height:8px}.fa-icon-button:hover{color:maroon;-webkit-transition:color .25s linear;transition:color .25s linear}
.editable-text{cursor:pointer}
.editable-text:hover{cursor:text;border:dotted #999999 1px}
.icon-button.multiinput{background:url(../images/documents-stack.png) no-repeat;cursor:pointer;float:none;display:inline-block;margin-left:10px}
diff -r edc5e6ad3d544c47457aaf135c7956d9ac0ab32b -r 47798b37aed096b344c43c6796b7aae27ef11e90 static/style/src/less/base.less
--- a/static/style/src/less/base.less
+++ b/static/style/src/less/base.less
@@ -1339,6 +1339,21 @@
padding: 0;
}
+.fa-icon-button {
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ cursor: pointer;
+ width: 16px;
+ height: 16px;
+ line-height: 8px;
+ // Fade to maroon on hover
+ &:hover {
+ color: maroon;
+ .transition(color .25s linear);
+ }
+}
+
.editable-text {
cursor:pointer;
}
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: MetadataFile shouldn't attempt to create by default without checking exists() first.
by commits-noreply@bitbucket.org 17 Sep '13
by commits-noreply@bitbucket.org 17 Sep '13
17 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6cf5d0cbaf96/
Changeset: 6cf5d0cbaf96
User: dannon
Date: 2013-09-17 20:56:56
Summary: MetadataFile shouldn't attempt to create by default without checking exists() first.
Affected #: 1 file
diff -r 96a2ab47b882690df5a2a962d3689474e4312e3a -r 6cf5d0cbaf96c9910b7e72a83f16d5c6a9f2f34a lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2416,7 +2416,8 @@
da = self.history_dataset or self.library_dataset
if self.object_store_id is None and da is not None:
self.object_store_id = da.dataset.object_store_id
- da.dataset.object_store.create( self, extra_dir='_metadata_files', extra_dir_at_root=True, alt_name="metadata_%d.dat" % self.id )
+ if not da.dataset.object_store.exists( self, extra_dir='_metadata_files', extra_dir_at_root=True, alt_name="metadata_%d.dat" % self.id ):
+ da.dataset.object_store.create( self, extra_dir='_metadata_files', extra_dir_at_root=True, alt_name="metadata_%d.dat" % self.id )
path = da.dataset.object_store.get_filename( self, extra_dir='_metadata_files', extra_dir_at_root=True, alt_name="metadata_%d.dat" % self.id )
return path
except AttributeError:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Richard Burhans: Fix integrated_tool_panel dictionary before writing integrated_tool_panel.xml to keep tools/workflows in multiple sections
by commits-noreply@bitbucket.org 17 Sep '13
by commits-noreply@bitbucket.org 17 Sep '13
17 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/96a2ab47b882/
Changeset: 96a2ab47b882
User: Richard Burhans
Date: 2013-09-17 20:37:36
Summary: Fix integrated_tool_panel dictionary before writing integrated_tool_panel.xml to keep tools/workflows in multiple sections
Affected #: 1 file
diff -r 48fad71361b3075c85c7d365dd52c106cabad73a -r 96a2ab47b882690df5a2a962d3689474e4312e3a lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -154,8 +154,24 @@
# This will cover cases where the Galaxy administrator manually edited one or more of the tool panel
# config files, adding or removing locally developed tools or workflows. The value of integrated_tool_panel
# will be False when things like functional tests are the caller.
+ self.fix_integrated_tool_panel_dict()
self.write_integrated_tool_panel_config_file()
+ def fix_integrated_tool_panel_dict( self ):
+ # HACK: instead of fixing after the fact, I suggest some combination of:
+ # 1) adjusting init_tools() and called methods to get this right
+ # 2) redesigning the code and/or data structure used to read/write integrated_tool_panel.xml
+ for key, value in self.integrated_tool_panel.iteritems():
+ if key.startswith( 'section_' ):
+ for section_key, section_value in value.elems.iteritems():
+ if section_value is None:
+ if section_key.startswith( 'tool_' ):
+ tool_id = section_key[5:]
+ value.elems[section_key] = self.tools_by_id.get( tool_id )
+ elif section_key.startswith( 'workflow_' ):
+ workflow_id = section_key[9:]
+ value.elems[section_key] = self.workflows_by_id.get( workflow_id )
+
def init_tools( self, config_filename ):
"""
Read the configuration file and load each tool. The following tags are currently supported:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
8 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5196dc5182f6/
Changeset: 5196dc5182f6
Branch: tool_api_submit
User: Kyle Ellrott
Date: 2013-06-27 23:23:12
Summary: Adding 'history' parameter to 'get_initial_value' method calls. This allows api based tool requests to build default parameters without having a fixed history attached to the 'trans' class
Affected #: 3 files
diff -r 63b58d89dedd942ad9842958476dd9d364fe1fe0 -r 5196dc5182f6595b1978cc52359f49547a4a2706 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1814,7 +1814,7 @@
# TODO: Anyway to capture tools that dynamically change their own
# outputs?
return True
- def new_state( self, trans, all_pages=False ):
+ def new_state( self, trans, all_pages=False, history=None ):
"""
Create a new `DefaultToolState` for this tool. It will be initialized
with default values for inputs.
@@ -1828,16 +1828,16 @@
inputs = self.inputs
else:
inputs = self.inputs_by_page[ 0 ]
- self.fill_in_new_state( trans, inputs, state.inputs )
+ self.fill_in_new_state( trans, inputs, state.inputs, history=history )
return state
- def fill_in_new_state( self, trans, inputs, state, context=None ):
+ def fill_in_new_state( self, trans, inputs, state, context=None, history=None ):
"""
Fill in a tool state dictionary with default values for all parameters
in the dictionary `inputs`. Grouping elements are filled in recursively.
"""
context = ExpressionContext( state, context )
for input in inputs.itervalues():
- state[ input.name ] = input.get_initial_value( trans, context )
+ state[ input.name ] = input.get_initial_value( trans, context, history=history )
def get_param_html_map( self, trans, page=0, other_values={} ):
"""
Return a dictionary containing the HTML representation of each
@@ -1900,7 +1900,7 @@
state = DefaultToolState()
state.decode( encoded_state, self, trans.app )
else:
- state = self.new_state( trans )
+ state = self.new_state( trans, history=history )
# This feels a bit like a hack. It allows forcing full processing
# of inputs even when there is no state in the incoming dictionary
# by providing either 'runtool_btn' (the name of the submit button
diff -r 63b58d89dedd942ad9842958476dd9d364fe1fe0 -r 5196dc5182f6595b1978cc52359f49547a4a2706 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -69,13 +69,13 @@
"""
return value
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
"""
Return the starting value of the parameter
"""
return None
- def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used ):
+ def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ):
"""
Get the starting value for the parameter, but if fetching from the history, try
to find a value that has not yet been used. already_used is a list of objects that
@@ -83,7 +83,7 @@
if a value has already been chosen from the history. This is to support the capability to
choose each dataset once
"""
- return self.get_initial_value(trans, context);
+ return self.get_initial_value(trans, context, history=history);
def get_required_enctype( self ):
"""
@@ -204,7 +204,7 @@
return form_builder.TextArea( self.name, self.size, value )
else:
return form_builder.TextField( self.name, self.size, value )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
class IntegerToolParameter( TextToolParameter ):
@@ -271,7 +271,7 @@
if not value and self.optional:
return None
raise err
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
if self.value:
return int( self.value )
else:
@@ -340,7 +340,7 @@
if not value and self.optional:
return None
raise err
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
try:
return float( self.value )
except:
@@ -383,7 +383,7 @@
return [ 'true' ]
def to_python( self, value, app ):
return ( value == 'True' )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.checked
def to_param_dict_string( self, value, other_values={} ):
if value:
@@ -456,7 +456,7 @@
return value
else:
raise Exception( "FileToolParameter cannot be persisted" )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
class FTPFileToolParameter( ToolParameter ):
@@ -495,7 +495,7 @@
return None
elif isinstance( value, unicode ) or isinstance( value, str ) or isinstance( value, list ):
return value
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
class HiddenToolParameter( ToolParameter ):
@@ -516,7 +516,7 @@
self.value = elem.get( 'value' )
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.HiddenField( self.name, self.value )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
def get_label( self ):
return None
@@ -539,7 +539,7 @@
return url
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.HiddenField( self.name, self.get_value( trans ) )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
def get_label( self ):
# BaseURLToolParameters are ultimately "hidden" parameters
@@ -805,7 +805,7 @@
return True
# Dynamic, but all dependenceis are known and have values
return False
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
# More working around dynamic options for workflow
if self.need_late_validation( trans, context ):
# Really the best we can do?
@@ -1035,7 +1035,7 @@
options.append( ( 'c' + col, col, False ) )
return options
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
if self.default_value is not None:
# dataset not ready / in workflow / etc
if self.need_late_validation( trans, context ):
@@ -1315,7 +1315,7 @@
rval = sanitize_param( rval )
return rval
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
def recurse_options( initial_values, options ):
for option in options:
if option['selected']:
@@ -1503,10 +1503,10 @@
field.add_option( "Selection is Optional", 'None', False )
return field
- def get_initial_value( self, trans, context ):
- return self.get_initial_value_from_history_prevent_repeats(trans, context, None);
+ def get_initial_value( self, trans, context, history=None ):
+ return self.get_initial_value_from_history_prevent_repeats(trans, context, None, history=history);
- def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used ):
+ def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ):
"""
NOTE: This is wasteful since dynamic options and dataset collection
happens twice (here and when generating HTML).
@@ -1515,7 +1515,8 @@
if trans is None or trans.workflow_building_mode:
return DummyDataset()
assert trans is not None, "DataToolParameter requires a trans"
- history = trans.get_history()
+ if history is None:
+ history = trans.get_history()
assert history is not None, "DataToolParameter requires a history"
if self.optional:
return None
@@ -1687,7 +1688,7 @@
DataToolParameter.__init__( self, tool, elem )
self.value = "None"
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
def get_html_field( self, trans=None, value=None, other_values={} ):
diff -r 63b58d89dedd942ad9842958476dd9d364fe1fe0 -r 5196dc5182f6595b1978cc52359f49547a4a2706 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -34,7 +34,7 @@
into the preferred value form.
"""
return value
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
"""
Return the initial state/value for this group
"""
@@ -96,7 +96,7 @@
callback( new_prefix, input, d[input.name], parent = d )
else:
input.visit_inputs( new_prefix, d[input.name], callback )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
rval = []
for i in range( self.default ):
rval_dict = { '__index__': i}
@@ -189,14 +189,14 @@
callback( new_prefix, input, d[input.name], parent = d )
else:
input.visit_inputs( new_prefix, d[input.name], callback )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
d_type = self.get_datatype( trans, context )
rval = []
for i, ( composite_name, composite_file ) in enumerate( d_type.writable_files.iteritems() ):
rval_dict = {}
rval_dict['__index__'] = i # create __index__
for input in self.inputs.itervalues():
- rval_dict[ input.name ] = input.get_initial_value( trans, context ) #input.value_to_basic( d[input.name], app )
+ rval_dict[ input.name ] = input.get_initial_value( trans, context, history=history ) #input.value_to_basic( d[input.name], app )
rval.append( rval_dict )
return rval
def get_uploaded_datasets( self, trans, context, override_name = None, override_info = None ):
@@ -476,12 +476,12 @@
callback( prefix, input, value[input.name], parent = value )
else:
input.visit_inputs( prefix, value[input.name], callback )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
# State for a conditional is a plain dictionary.
rval = {}
# Get the default value for the 'test element' and use it
# to determine the current case
- test_value = self.test_param.get_initial_value( trans, context )
+ test_value = self.test_param.get_initial_value( trans, context, history=None )
current_case = self.get_current_case( test_value, trans )
# Store the current case in a special value
rval['__current_case__'] = current_case
@@ -490,7 +490,7 @@
# Fill in state for selected case
child_context = ExpressionContext( rval, context )
for child_input in self.cases[current_case].inputs.itervalues():
- rval[ child_input.name ] = child_input.get_initial_value( trans, child_context )
+ rval[ child_input.name ] = child_input.get_initial_value( trans, child_context, history=None )
return rval
class ConditionalWhen( object ):
https://bitbucket.org/galaxy/galaxy-central/commits/7ac0ed6f42d6/
Changeset: 7ac0ed6f42d6
Branch: tool_api_submit
User: Kyle Ellrott
Date: 2013-06-27 23:58:14
Summary: Removing stray print statement
Affected #: 1 file
diff -r 5196dc5182f6595b1978cc52359f49547a4a2706 -r 7ac0ed6f42d64e24f7bd851193368184a5e28def lib/galaxy/model/migrate/check.py
--- a/lib/galaxy/model/migrate/check.py
+++ b/lib/galaxy/model/migrate/check.py
@@ -44,7 +44,6 @@
# Let this go, it could possibly work with db's we don't support
log.error( "database_connection contains an unknown SQLAlchemy database dialect: %s" % dialect )
# Create engine and metadata
- print url, engine_options
engine = create_engine( url, **engine_options )
meta = MetaData( bind=engine )
# Try to load dataset table
https://bitbucket.org/galaxy/galaxy-central/commits/371e3b451448/
Changeset: 371e3b451448
Branch: tool_api_submit
User: Kyle Ellrott
Date: 2013-06-28 00:52:08
Summary: The /api/tool submit can define inputs in the payload in the format {'id' : <encoded_id>, 'src' : 'hda'}
Affected #: 1 file
diff -r 7ac0ed6f42d64e24f7bd851193368184a5e28def -r 371e3b451448bfb7a70139faafc33072a7d2b468 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -1575,6 +1575,9 @@
rval = [ trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( v ) for v in value ]
elif isinstance( value, trans.app.model.HistoryDatasetAssociation ):
rval = value
+ elif isinstance( value, dict ) and 'src' in value and 'id' in value:
+ if value['src'] == 'hda':
+ rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.app.security.decode_id(value['id']) )
else:
rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( value )
if isinstance( rval, list ):
https://bitbucket.org/galaxy/galaxy-central/commits/abb889f8c5b7/
Changeset: abb889f8c5b7
Branch: tool_api_submit
User: Kyle Ellrott
Date: 2013-07-03 22:38:40
Summary: Adding way for API based tools job submissions to copy library dataset into history
Affected #: 1 file
diff -r 371e3b451448bfb7a70139faafc33072a7d2b468 -r abb889f8c5b75e8b90e8a35617e95ec7c05d28e7 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -30,10 +30,10 @@
# Read params.
in_panel = util.string_as_bool( kwds.get( 'in_panel', 'True' ) )
trackster = util.string_as_bool( kwds.get( 'trackster', 'False' ) )
-
+
# Create return value.
try:
- return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster )
+ return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster)
except Exception, exc:
log.error( 'could not convert toolbox to dictionary: %s', str( exc ), exc_info=True )
trans.response.status = 500
@@ -87,6 +87,17 @@
for k, v in payload.iteritems():
if k.startswith("files_"):
inputs[k] = v
+
+ #for inputs that are coming from the Library, copy them into the history
+ input_patch = {}
+ for k, v in inputs.iteritems():
+ if isinstance(v, dict) and v.get('src', '') == 'ldda' and 'id' in v:
+ ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id(v['id']) )
+ if trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset ):
+ input_patch[k] = ldda.to_history_dataset_association(target_history, add_to_history=True)
+
+ for k, v in input_patch.iteritems():
+ inputs[k] = v
# HACK: add run button so that tool.handle_input will run tool.
inputs['runtool_btn'] = 'Execute'
https://bitbucket.org/galaxy/galaxy-central/commits/d370b6ba1443/
Changeset: d370b6ba1443
User: Kyle Ellrott
Date: 2013-06-27 23:23:12
Summary: Adding 'history' parameter to 'get_initial_value' method calls. This allows api based tool requests to build default parameters without having a fixed history attached to the 'trans' class
Affected #: 3 files
diff -r 44214ff2a8801dea8714b6cfc7f2d7bd6545e229 -r d370b6ba1443adf67390ae8ca7b8d71a9746b3f6 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1852,7 +1852,7 @@
# TODO: Anyway to capture tools that dynamically change their own
# outputs?
return True
- def new_state( self, trans, all_pages=False ):
+ def new_state( self, trans, all_pages=False, history=None ):
"""
Create a new `DefaultToolState` for this tool. It will be initialized
with default values for inputs.
@@ -1866,16 +1866,16 @@
inputs = self.inputs
else:
inputs = self.inputs_by_page[ 0 ]
- self.fill_in_new_state( trans, inputs, state.inputs )
+ self.fill_in_new_state( trans, inputs, state.inputs, history=history )
return state
- def fill_in_new_state( self, trans, inputs, state, context=None ):
+ def fill_in_new_state( self, trans, inputs, state, context=None, history=None ):
"""
Fill in a tool state dictionary with default values for all parameters
in the dictionary `inputs`. Grouping elements are filled in recursively.
"""
context = ExpressionContext( state, context )
for input in inputs.itervalues():
- state[ input.name ] = input.get_initial_value( trans, context )
+ state[ input.name ] = input.get_initial_value( trans, context, history=history )
def get_param_html_map( self, trans, page=0, other_values={} ):
"""
Return a dictionary containing the HTML representation of each
@@ -1938,7 +1938,7 @@
state = DefaultToolState()
state.decode( encoded_state, self, trans.app )
else:
- state = self.new_state( trans )
+ state = self.new_state( trans, history=history )
# This feels a bit like a hack. It allows forcing full processing
# of inputs even when there is no state in the incoming dictionary
# by providing either 'runtool_btn' (the name of the submit button
diff -r 44214ff2a8801dea8714b6cfc7f2d7bd6545e229 -r d370b6ba1443adf67390ae8ca7b8d71a9746b3f6 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -72,13 +72,13 @@
"""
return value
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
"""
Return the starting value of the parameter
"""
return None
- def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used ):
+ def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ):
"""
Get the starting value for the parameter, but if fetching from the history, try
to find a value that has not yet been used. already_used is a list of objects that
@@ -86,7 +86,7 @@
if a value has already been chosen from the history. This is to support the capability to
choose each dataset once
"""
- return self.get_initial_value(trans, context);
+ return self.get_initial_value(trans, context, history=history);
def get_required_enctype( self ):
"""
@@ -216,7 +216,7 @@
return form_builder.TextArea( self.name, self.size, value )
else:
return form_builder.TextField( self.name, self.size, value )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
class IntegerToolParameter( TextToolParameter ):
@@ -286,7 +286,7 @@
if not value and self.optional:
return None
raise err
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
if self.value:
return int( self.value )
else:
@@ -358,7 +358,7 @@
if not value and self.optional:
return None
raise err
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
try:
return float( self.value )
except:
@@ -401,7 +401,7 @@
return [ 'true' ]
def to_python( self, value, app ):
return ( value == 'True' )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.checked
def to_param_dict_string( self, value, other_values={} ):
if value:
@@ -474,7 +474,7 @@
return value
else:
raise Exception( "FileToolParameter cannot be persisted" )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
class FTPFileToolParameter( ToolParameter ):
@@ -513,7 +513,7 @@
return None
elif isinstance( value, unicode ) or isinstance( value, str ) or isinstance( value, list ):
return value
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
class HiddenToolParameter( ToolParameter ):
@@ -534,7 +534,7 @@
self.value = elem.get( 'value' )
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.HiddenField( self.name, self.value )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
def get_label( self ):
return None
@@ -557,7 +557,7 @@
return url
def get_html_field( self, trans=None, value=None, other_values={} ):
return form_builder.HiddenField( self.name, self.get_value( trans ) )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return self.value
def get_label( self ):
# BaseURLToolParameters are ultimately "hidden" parameters
@@ -826,7 +826,7 @@
return True
# Dynamic, but all dependenceis are known and have values
return False
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
# More working around dynamic options for workflow
if self.need_late_validation( trans, context ):
# Really the best we can do?
@@ -1074,7 +1074,7 @@
options.append( ( 'c' + col, col, False ) )
return options
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
if self.default_value is not None:
# dataset not ready / in workflow / etc
if self.need_late_validation( trans, context ):
@@ -1353,8 +1353,7 @@
else:
rval = sanitize_param( rval )
return rval
-
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
def recurse_options( initial_values, options ):
for option in options:
if option['selected']:
@@ -1542,10 +1541,10 @@
field.add_option( "Selection is Optional", 'None', False )
return field
- def get_initial_value( self, trans, context ):
- return self.get_initial_value_from_history_prevent_repeats(trans, context, None);
+ def get_initial_value( self, trans, context, history=None ):
+ return self.get_initial_value_from_history_prevent_repeats(trans, context, None, history=history);
- def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used ):
+ def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ):
"""
NOTE: This is wasteful since dynamic options and dataset collection
happens twice (here and when generating HTML).
@@ -1554,7 +1553,8 @@
if trans is None or trans.workflow_building_mode or trans.webapp.name == 'tool_shed':
return DummyDataset()
assert trans is not None, "DataToolParameter requires a trans"
- history = trans.get_history()
+ if history is None:
+ history = trans.get_history()
assert history is not None, "DataToolParameter requires a history"
if self.optional:
return None
@@ -1727,7 +1727,7 @@
self.value = "None"
self.type = "hidden_data"
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
return None
def get_html_field( self, trans=None, value=None, other_values={} ):
diff -r 44214ff2a8801dea8714b6cfc7f2d7bd6545e229 -r d370b6ba1443adf67390ae8ca7b8d71a9746b3f6 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -41,8 +41,7 @@
into the preferred value form.
"""
return value
-
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
"""
Return the initial state/value for this group
"""
@@ -109,7 +108,7 @@
callback( new_prefix, input, d[input.name], parent = d )
else:
input.visit_inputs( new_prefix, d[input.name], callback )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
rval = []
for i in range( self.default ):
rval_dict = { '__index__': i}
@@ -202,14 +201,14 @@
callback( new_prefix, input, d[input.name], parent = d )
else:
input.visit_inputs( new_prefix, d[input.name], callback )
- def get_initial_value( self, trans, context ):
+ def get_initial_value( self, trans, context, history=None ):
d_type = self.get_datatype( trans, context )
rval = []
for i, ( composite_name, composite_file ) in enumerate( d_type.writable_files.iteritems() ):
rval_dict = {}
rval_dict['__index__'] = i # create __index__
for input in self.inputs.itervalues():
- rval_dict[ input.name ] = input.get_initial_value( trans, context ) #input.value_to_basic( d[input.name], app )
+ rval_dict[ input.name ] = input.get_initial_value( trans, context, history=history ) #input.value_to_basic( d[input.name], app )
rval.append( rval_dict )
return rval
def get_uploaded_datasets( self, trans, context, override_name = None, override_info = None ):
@@ -489,12 +488,12 @@
callback( prefix, input, value[input.name], parent = value )
else:
input.visit_inputs( prefix, value[input.name], callback )
- def get_initial_value( self, trans, context ):
- # State for a conditional is a plain dictionary.
+ def get_initial_value( self, trans, context, history=None ):
+ # State for a conditional is a plain dictionary.
rval = {}
# Get the default value for the 'test element' and use it
# to determine the current case
- test_value = self.test_param.get_initial_value( trans, context )
+ test_value = self.test_param.get_initial_value( trans, context, history=None )
current_case = self.get_current_case( test_value, trans )
# Store the current case in a special value
rval['__current_case__'] = current_case
@@ -503,7 +502,7 @@
# Fill in state for selected case
child_context = ExpressionContext( rval, context )
for child_input in self.cases[current_case].inputs.itervalues():
- rval[ child_input.name ] = child_input.get_initial_value( trans, child_context )
+ rval[ child_input.name ] = child_input.get_initial_value( trans, child_context, history=None )
return rval
class ConditionalWhen( object ):
https://bitbucket.org/galaxy/galaxy-central/commits/3e086bca9f63/
Changeset: 3e086bca9f63
User: Kyle Ellrott
Date: 2013-06-28 00:52:08
Summary: The /api/tool submit can define inputs in the payload in the format {'id' : <encoded_id>, 'src' : 'hda'}
Affected #: 1 file
diff -r d370b6ba1443adf67390ae8ca7b8d71a9746b3f6 -r 3e086bca9f63e270da8cbd7e65feb0b22a0ae085 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -1613,6 +1613,9 @@
rval = [ trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( v ) for v in value ]
elif isinstance( value, trans.app.model.HistoryDatasetAssociation ):
rval = value
+ elif isinstance( value, dict ) and 'src' in value and 'id' in value:
+ if value['src'] == 'hda':
+ rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.app.security.decode_id(value['id']) )
else:
rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( value )
if isinstance( rval, list ):
https://bitbucket.org/galaxy/galaxy-central/commits/48fad71361b3/
Changeset: 48fad71361b3
User: Kyle Ellrott
Date: 2013-07-03 22:38:40
Summary: Adding way for API based tools job submissions to copy library dataset into history
Affected #: 1 file
diff -r 3e086bca9f63e270da8cbd7e65feb0b22a0ae085 -r 48fad71361b3075c85c7d365dd52c106cabad73a lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -32,7 +32,7 @@
# Create return value.
try:
- return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster )
+ return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster)
except Exception, exc:
log.error( 'could not convert toolbox to dictionary: %s', str( exc ), exc_info=True )
trans.response.status = 500
@@ -86,6 +86,17 @@
for k, v in payload.iteritems():
if k.startswith("files_"):
inputs[k] = v
+
+ #for inputs that are coming from the Library, copy them into the history
+ input_patch = {}
+ for k, v in inputs.iteritems():
+ if isinstance(v, dict) and v.get('src', '') == 'ldda' and 'id' in v:
+ ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id(v['id']) )
+ if trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset ):
+ input_patch[k] = ldda.to_history_dataset_association(target_history, add_to_history=True)
+
+ for k, v in input_patch.iteritems():
+ inputs[k] = v
# HACK: add run button so that tool.handle_input will run tool.
inputs['runtool_btn'] = 'Execute'
https://bitbucket.org/galaxy/galaxy-central/commits/e3e7b034cb0b/
Changeset: e3e7b034cb0b
Branch: tool_api_submit
User: carlfeberhard
Date: 2013-09-16 21:45:04
Summary: Close branch tool_api_submit
Affected #: 0 files
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Use to_html_string on failed tests tracebacks and stderr
by commits-noreply@bitbucket.org 16 Sep '13
by commits-noreply@bitbucket.org 16 Sep '13
16 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/44214ff2a880/
Changeset: 44214ff2a880
User: dan
Date: 2013-09-16 17:12:26
Summary: Use to_html_string on failed tests tracebacks and stderr
Affected #: 1 file
diff -r b65602624e257d96d90fe94de13b483fd70d2f7e -r 44214ff2a8801dea8714b6cfc7f2d7bd6545e229 templates/webapps/tool_shed/repository/common.mako
--- a/templates/webapps/tool_shed/repository/common.mako
+++ b/templates/webapps/tool_shed/repository/common.mako
@@ -439,7 +439,10 @@
</%def><%def name="render_failed_test( failed_test, pad, parent, row_counter, row_is_header=False )">
- <% encoded_id = trans.security.encode_id( failed_test.id ) %>
+ <%
+ from tool_shed.util.shed_util_common import to_html_string
+ encoded_id = trans.security.encode_id( failed_test.id )
+ %><tr class="datasetRow"
%if parent is not None:
parent="${parent}"
@@ -450,8 +453,8 @@
<tr><td bgcolor="#FFFFCC"><b>Tool id:</b> ${failed_test.tool_id | h}</td></tr><tr><td><b>Tool version:</b> ${failed_test.tool_id | h}</td></tr><tr><td><b>Test:</b> ${failed_test.test_id | h}</td></tr>
- <tr><td><b>Stderr:</b><br/>${failed_test.stderr | h}</td></tr>
- <tr><td><b>Traceback:</b><br/>${failed_test.traceback | h}</td></tr>
+ <tr><td><b>Stderr:</b><br/>${ to_html_string( failed_test.stderr ) }</td></tr>
+ <tr><td><b>Traceback:</b><br/>${ to_html_string( failed_test.traceback ) }</td></tr></table></td></tr>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0