| 1 | ## Render a tool |
|---|
| 2 | <%def name="render_tool( tool, section )"> |
|---|
| 3 | %if not tool.hidden: |
|---|
| 4 | %if section: |
|---|
| 5 | <div class="toolTitle"> |
|---|
| 6 | %else: |
|---|
| 7 | <div class="toolTitleNoSection"> |
|---|
| 8 | %endif |
|---|
| 9 | <% |
|---|
| 10 | if tool.input_required: |
|---|
| 11 | link = h.url_for( controller='tool_runner', tool_id=tool.id ) |
|---|
| 12 | else: |
|---|
| 13 | link = h.url_for( tool.action, ** tool.get_static_param_values( t ) ) |
|---|
| 14 | %> |
|---|
| 15 | ## FIXME: This doesn't look right |
|---|
| 16 | ## %if "[[" in tool.description and "]]" in tool.description: |
|---|
| 17 | ## ${tool.description.replace( '[[', '<a href="link" target="galaxy_main">' % $tool.id ).replace( "]]", "</a>" ) |
|---|
| 18 | %if tool.name: |
|---|
| 19 | <a id="link-${tool.id}" href="${link}" target=${tool.target} minsizehint="${tool.uihints.get( 'minwidth', -1 )}">${_(tool.name)}</a> ${tool.description} |
|---|
| 20 | %else: |
|---|
| 21 | <a id="link-${tool.id}" href="${link}" target=${tool.target} minsizehint="${tool.uihints.get( 'minwidth', -1 )}">${tool.description}</a> |
|---|
| 22 | %endif |
|---|
| 23 | </div> |
|---|
| 24 | %endif |
|---|
| 25 | </%def> |
|---|
| 26 | |
|---|
| 27 | ## Render a workflow |
|---|
| 28 | <%def name="render_workflow( key, workflow, section )"> |
|---|
| 29 | %if section: |
|---|
| 30 | <div class="toolTitle"> |
|---|
| 31 | %else: |
|---|
| 32 | <div class="toolTitleNoSection"> |
|---|
| 33 | %endif |
|---|
| 34 | <% encoded_id = key.lstrip( 'workflow_' ) %> |
|---|
| 35 | <a id="link-${workflow.id}" href="${ h.url_for( controller='workflow', action='run', id=encoded_id, check_user=False )}" target="_parent"}">${_(workflow.name)}</a> |
|---|
| 36 | </div> |
|---|
| 37 | </%def> |
|---|
| 38 | |
|---|
| 39 | ## Render a label |
|---|
| 40 | <%def name="render_label( label )"> |
|---|
| 41 | <div class="toolPanelLabel" id="title_${label.id}"> |
|---|
| 42 | <span>${label.text}</span> |
|---|
| 43 | </div> |
|---|
| 44 | </%def> |
|---|
| 45 | |
|---|
| 46 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
|---|
| 47 | <html> |
|---|
| 48 | <head> |
|---|
| 49 | <title>${_('Galaxy Tools')}</title> |
|---|
| 50 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
|---|
| 51 | <link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" /> |
|---|
| 52 | <link href="${h.url_for('/static/style/tool_menu.css')}" rel="stylesheet" type="text/css" /> |
|---|
| 53 | |
|---|
| 54 | ##<script type="text/javascript" src="${h.url_for('/static/scripts/jquery.js')}"></script> |
|---|
| 55 | ${h.js( "jquery", "galaxy.base", "json2" )} |
|---|
| 56 | |
|---|
| 57 | <script type="text/javascript"> |
|---|
| 58 | // Set up GalaxyAsync object. |
|---|
| 59 | var galaxy_async = new GalaxyAsync(${str(trans.app.config.log_actions).lower()}); |
|---|
| 60 | galaxy_async.set_func_url(galaxy_async.log_user_action, "${h.url_for( controller='user', action='log_user_action_async' )}"); |
|---|
| 61 | |
|---|
| 62 | $(document).ready(function() { |
|---|
| 63 | // Init showing/hiding of tool sections. |
|---|
| 64 | $( "div.toolSectionBody" ).hide(); |
|---|
| 65 | $( "div.toolSectionTitle > span" ).wrap( "<a href='#'></a>" ) |
|---|
| 66 | var last_expanded = null; |
|---|
| 67 | $( "div.toolSectionTitle" ).each( function() { |
|---|
| 68 | var body = $(this).next( "div.toolSectionBody" ); |
|---|
| 69 | $(this).click( function() { |
|---|
| 70 | if ( body.is( ":hidden" ) ) { |
|---|
| 71 | if ( last_expanded ) { |
|---|
| 72 | last_expanded.slideUp( "fast" ); |
|---|
| 73 | } |
|---|
| 74 | last_expanded = body; |
|---|
| 75 | body.slideDown( "fast" ); |
|---|
| 76 | } |
|---|
| 77 | else { |
|---|
| 78 | body.slideUp( "fast" ); |
|---|
| 79 | last_expanded = null; |
|---|
| 80 | } |
|---|
| 81 | return false; |
|---|
| 82 | }); |
|---|
| 83 | }); |
|---|
| 84 | |
|---|
| 85 | // Log clicks on tools. |
|---|
| 86 | $("div.toolTitle > a").click( function() |
|---|
| 87 | { |
|---|
| 88 | var tool_title = $(this).attr('id').split("-")[1]; |
|---|
| 89 | var section_title = $(this).parents("div.toolSectionWrapper").find("div.toolSectionTitle").text().trim(); |
|---|
| 90 | var search_active = $(this).parents("div.toolTitle").hasClass("search_match"); |
|---|
| 91 | |
|---|
| 92 | // Log action. |
|---|
| 93 | galaxy_async.log_user_action("tool_menu_click." + tool_title, section_title, |
|---|
| 94 | JSON.stringify({"search_active" : search_active})); |
|---|
| 95 | }); |
|---|
| 96 | |
|---|
| 97 | $( "a[minsizehint]" ).click( function() { |
|---|
| 98 | if ( parent.handle_minwidth_hint ) { |
|---|
| 99 | parent.handle_minwidth_hint( $(this).attr( "minsizehint" ) ); |
|---|
| 100 | } |
|---|
| 101 | }); |
|---|
| 102 | |
|---|
| 103 | // Init searching. |
|---|
| 104 | $("#tool-search-query").click( function (){ |
|---|
| 105 | $(this).focus(); |
|---|
| 106 | $(this).select(); |
|---|
| 107 | }) |
|---|
| 108 | .keyup( function () { |
|---|
| 109 | // Remove italics. |
|---|
| 110 | $(this).css("font-style", "normal"); |
|---|
| 111 | |
|---|
| 112 | // Don't update if same value as last time |
|---|
| 113 | if ( this.value.length < 3 ) { |
|---|
| 114 | reset_tool_search(false); |
|---|
| 115 | } else if ( this.value != this.lastValue ) { |
|---|
| 116 | // Add class to denote that searching is active. |
|---|
| 117 | $(this).addClass("search_active"); |
|---|
| 118 | // input.addClass(config.loadingClass); |
|---|
| 119 | // Add '*' to facilitate partial matching. |
|---|
| 120 | var q = this.value + '*'; |
|---|
| 121 | // Stop previous ajax-request |
|---|
| 122 | if (this.timer) { |
|---|
| 123 | clearTimeout(this.timer); |
|---|
| 124 | } |
|---|
| 125 | // Start a new ajax-request in X ms |
|---|
| 126 | $("#search-spinner").show(); |
|---|
| 127 | this.timer = setTimeout(function () { |
|---|
| 128 | $.get("${h.url_for( controller='root', action='tool_search' )}", { query: q }, function (data) { |
|---|
| 129 | // input.removeClass(config.loadingClass); |
|---|
| 130 | // Show live-search if results and search-term aren't empty |
|---|
| 131 | $("#search-no-results").hide(); |
|---|
| 132 | // Hide all tool sections. |
|---|
| 133 | $(".toolSectionWrapper").hide(); |
|---|
| 134 | // This hides all tools but not workflows link (which is in a .toolTitle div). |
|---|
| 135 | $(".toolSectionWrapper").find(".toolTitle").hide(); |
|---|
| 136 | if ( data.length != 0 ) { |
|---|
| 137 | // Map tool ids to element ids and join them. |
|---|
| 138 | var s = $.map( data, function( n, i ) { return "#link-" + n; } ).join( ", " ); |
|---|
| 139 | |
|---|
| 140 | // First pass to show matching tools and their parents. |
|---|
| 141 | $(s).each( function() { |
|---|
| 142 | // Add class to denote match. |
|---|
| 143 | $(this).parent().addClass("search_match"); |
|---|
| 144 | if ($(this).parents("#recently_used_wrapper").length == 0) |
|---|
| 145 | // Default behavior. |
|---|
| 146 | $(this).parent().show().parent().parent().show().parent().show(); |
|---|
| 147 | else if ($(this).parents(".user_pref_visible").length != 0) |
|---|
| 148 | // RU menu is visible, so filter it as normal. |
|---|
| 149 | $(this).parent().show().parent().parent().show().parent().show(); |
|---|
| 150 | else |
|---|
| 151 | { |
|---|
| 152 | // RU menu is not visible, so set up classes and visibility so that if menu shown matching is |
|---|
| 153 | // aleady in place. |
|---|
| 154 | $(this).parent().show(); |
|---|
| 155 | } |
|---|
| 156 | }); |
|---|
| 157 | |
|---|
| 158 | // Hide labels that have no visible children. |
|---|
| 159 | $(".toolPanelLabel").each( function() { |
|---|
| 160 | var this_label = $(this); |
|---|
| 161 | var next = this_label.next(); |
|---|
| 162 | var no_visible_tools = true; |
|---|
| 163 | // Look through tools following label and, if none are visible, hide label. |
|---|
| 164 | while (next.length != 0 && next.hasClass("toolTitle")) |
|---|
| 165 | { |
|---|
| 166 | if (next.is(":visible")) |
|---|
| 167 | { |
|---|
| 168 | no_visible_tools = false; |
|---|
| 169 | break; |
|---|
| 170 | } |
|---|
| 171 | else |
|---|
| 172 | next = next.next(); |
|---|
| 173 | } |
|---|
| 174 | if (no_visible_tools) |
|---|
| 175 | this_label.hide(); |
|---|
| 176 | }); |
|---|
| 177 | } else { |
|---|
| 178 | $("#search-no-results").show(); |
|---|
| 179 | } |
|---|
| 180 | $("#search-spinner").hide(); |
|---|
| 181 | }, "json" ); |
|---|
| 182 | }, 200 ); |
|---|
| 183 | } |
|---|
| 184 | this.lastValue = this.value; |
|---|
| 185 | }); |
|---|
| 186 | }); |
|---|
| 187 | |
|---|
| 188 | // Update recently used tools menu. Function inserts a new item and removes the last item. |
|---|
| 189 | function update_recently_used() |
|---|
| 190 | { |
|---|
| 191 | $.ajax({ |
|---|
| 192 | url: "${h.url_for( controller='/user', action='get_most_recently_used_tool_async' )}", |
|---|
| 193 | dataType: 'json', |
|---|
| 194 | error: function() { |
|---|
| 195 | // console.log( "Failed to update recently used list." ); |
|---|
| 196 | }, |
|---|
| 197 | success: function(new_tool_info) { |
|---|
| 198 | var recently_used_elts = $("#recently_used").find(".toolTitle"); |
|---|
| 199 | var first_elt = $(recently_used_elts.first()); |
|---|
| 200 | var found_in_list = false; |
|---|
| 201 | |
|---|
| 202 | // Look for new tool in current list. If found, rearrange list to move tool to top. |
|---|
| 203 | recently_used_elts.each( function(index) { |
|---|
| 204 | var anchor = $(this).find("a"); |
|---|
| 205 | var tool_id = anchor.attr("id").split("-")[1]; |
|---|
| 206 | if (tool_id == new_tool_info.id) |
|---|
| 207 | { |
|---|
| 208 | found_in_list = true; |
|---|
| 209 | |
|---|
| 210 | // If tool is first, do nothing. |
|---|
| 211 | if (index == 0) |
|---|
| 212 | return; |
|---|
| 213 | else |
|---|
| 214 | { |
|---|
| 215 | // Tool not first; reorder. |
|---|
| 216 | $(this).remove(); |
|---|
| 217 | first_elt.before($(this)); |
|---|
| 218 | } |
|---|
| 219 | } |
|---|
| 220 | }); |
|---|
| 221 | |
|---|
| 222 | // If tool not in list, create new element, remove last element, and put new element first in list. |
|---|
| 223 | if (!found_in_list) |
|---|
| 224 | { |
|---|
| 225 | new_tool_elt = $("<div class='toolTitle'> \ |
|---|
| 226 | <a id='link-" + new_tool_info.id + "' href='" + new_tool_info.link + "' target='" + |
|---|
| 227 | new_tool_info.target + "' minsizehint='" + new_tool_info.minsizehint + "'>" + |
|---|
| 228 | new_tool_info.name + "</a> " + new_tool_info.description + " \ |
|---|
| 229 | </div>"); |
|---|
| 230 | recently_used_elts.last().remove(); |
|---|
| 231 | recently_used_elts.first().before(new_tool_elt); |
|---|
| 232 | } |
|---|
| 233 | } |
|---|
| 234 | }); |
|---|
| 235 | } |
|---|
| 236 | </script> |
|---|
| 237 | </head> |
|---|
| 238 | |
|---|
| 239 | <body class="toolMenuPage"> |
|---|
| 240 | <div class="toolMenu"> |
|---|
| 241 | |
|---|
| 242 | ## Tool search. |
|---|
| 243 | <% |
|---|
| 244 | show_tool_search = False |
|---|
| 245 | if trans.user: |
|---|
| 246 | show_tool_search = trans.user.preferences.get( "show_tool_search", "False" ) |
|---|
| 247 | |
|---|
| 248 | if show_tool_search == "True": |
|---|
| 249 | display = "block" |
|---|
| 250 | else: |
|---|
| 251 | display = "none" |
|---|
| 252 | %> |
|---|
| 253 | <div id="tool-search" style="padding-bottom: 5px; position: relative; display: ${display}; width: 100%"> |
|---|
| 254 | <input type="text" name="query" value="search tools" id="tool-search-query" style="width: 100%; font-style:italic; font-size: inherit"/> |
|---|
| 255 | <img src="${h.url_for('/static/images/loading_small_white_bg.gif')}" id="search-spinner" style="display: none; position: absolute; right: 0; top: 5px;"/> |
|---|
| 256 | </div> |
|---|
| 257 | |
|---|
| 258 | ## Recently used tools. |
|---|
| 259 | %if trans.user: |
|---|
| 260 | <% |
|---|
| 261 | if trans.user.preferences.get( 'show_recently_used_menu', 'False' ) == 'True': |
|---|
| 262 | display = "block" |
|---|
| 263 | pref_class = "user_pref_visible" |
|---|
| 264 | else: |
|---|
| 265 | display = "none" |
|---|
| 266 | pref_class = "user_pref_hidden" |
|---|
| 267 | %> |
|---|
| 268 | <div class="toolSectionWrapper ${pref_class}" id="recently_used_wrapper" |
|---|
| 269 | style="display: ${display}; padding-bottom: 5px"> |
|---|
| 270 | <div class="toolSectionTitle"> |
|---|
| 271 | <span>Recently Used</span> |
|---|
| 272 | </div> |
|---|
| 273 | <div id="recently_used" class="toolSectionBody"> |
|---|
| 274 | <div class="toolSectionBg"> |
|---|
| 275 | %for tool in recent_tools: |
|---|
| 276 | ${render_tool( tool, True )} |
|---|
| 277 | %endfor |
|---|
| 278 | </div> |
|---|
| 279 | </div> |
|---|
| 280 | <div class="toolSectionPad"></div> |
|---|
| 281 | </div> |
|---|
| 282 | %endif |
|---|
| 283 | |
|---|
| 284 | ## Tools. |
|---|
| 285 | %for key, val in toolbox.tool_panel.items(): |
|---|
| 286 | <div class="toolSectionWrapper"> |
|---|
| 287 | %if key.startswith( 'tool' ): |
|---|
| 288 | ${render_tool( val, False )} |
|---|
| 289 | %elif key.startswith( 'workflow' ): |
|---|
| 290 | ${render_workflow( key, val, False )} |
|---|
| 291 | %elif key.startswith( 'section' ): |
|---|
| 292 | <% section = val %> |
|---|
| 293 | <div class="toolSectionTitle" id="title_${section.id}"> |
|---|
| 294 | <span>${section.name}</span> |
|---|
| 295 | </div> |
|---|
| 296 | <div id="${section.id}" class="toolSectionBody"> |
|---|
| 297 | <div class="toolSectionBg"> |
|---|
| 298 | %for section_key, section_val in section.elems.items(): |
|---|
| 299 | %if section_key.startswith( 'tool' ): |
|---|
| 300 | ${render_tool( section_val, True )} |
|---|
| 301 | %elif section_key.startswith( 'workflow' ): |
|---|
| 302 | ${render_workflow( section_key, section_val, True )} |
|---|
| 303 | %elif section_key.startswith( 'label' ): |
|---|
| 304 | ${render_label( section_val )} |
|---|
| 305 | %endif |
|---|
| 306 | %endfor |
|---|
| 307 | </div> |
|---|
| 308 | </div> |
|---|
| 309 | %elif key.startswith( 'label' ): |
|---|
| 310 | ${render_label( val )} |
|---|
| 311 | %endif |
|---|
| 312 | <div class="toolSectionPad"></div> |
|---|
| 313 | </div> |
|---|
| 314 | %endfor |
|---|
| 315 | |
|---|
| 316 | ## Feedback when search returns no results. |
|---|
| 317 | <div id="search-no-results" style="display: none; padding-top: 5px"> |
|---|
| 318 | <em><strong>Search did not match any tools.</strong></em> |
|---|
| 319 | </div> |
|---|
| 320 | |
|---|
| 321 | ## Link to workflow management. The location of this may change, but eventually |
|---|
| 322 | ## at least some workflows will appear here (the user should be able to |
|---|
| 323 | ## configure which of their stored workflows appear in the tools menu). |
|---|
| 324 | |
|---|
| 325 | %if t.user: |
|---|
| 326 | <div class="toolSectionPad"></div> |
|---|
| 327 | <div class="toolSectionPad"></div> |
|---|
| 328 | <div class="toolSectionTitle" id="title_XXinternalXXworkflow"> |
|---|
| 329 | <span>Workflows</span> |
|---|
| 330 | </div> |
|---|
| 331 | <div id="XXinternalXXworkflow" class="toolSectionBody"> |
|---|
| 332 | <div class="toolSectionBg"> |
|---|
| 333 | %if t.user.stored_workflow_menu_entries: |
|---|
| 334 | %for m in t.user.stored_workflow_menu_entries: |
|---|
| 335 | <div class="toolTitle"> |
|---|
| 336 | <a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(m.stored_workflow_id) )}" target="galaxy_main">${m.stored_workflow.name}</a> |
|---|
| 337 | </div> |
|---|
| 338 | %endfor |
|---|
| 339 | %endif |
|---|
| 340 | <div class="toolTitle"> |
|---|
| 341 | <a href="${h.url_for( controller='workflow', action='list_for_run')}" target="galaxy_main">All workflows</a> |
|---|
| 342 | </div> |
|---|
| 343 | </div> |
|---|
| 344 | </div> |
|---|
| 345 | %endif |
|---|
| 346 | |
|---|
| 347 | </div> |
|---|
| 348 | </div> |
|---|
| 349 | </body> |
|---|
| 350 | </html> |
|---|