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
- 15302 discussions
galaxy-dist commit f47ab71b2df3: Fix autocomplete select not closing after dragging text inside, and holding arrow keys not triggering multiple times in firefox. Cleanup JS
by commits-noreply@bitbucket.org 07 Jun '10
by commits-noreply@bitbucket.org 07 Jun '10
07 Jun '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kanwei Li <kanwei(a)gmail.com>
# Date 1275864909 14400
# Node ID f47ab71b2df3c27c7d231522c848b5e5ee2d2fe7
# Parent 9114bd0887769b9ffe570b71f90ab95be68baa44
Fix autocomplete select not closing after dragging text inside, and holding arrow keys not triggering multiple times in firefox. Cleanup JS
--- a/static/scripts/galaxy.base.js
+++ b/static/scripts/galaxy.base.js
@@ -147,7 +147,7 @@ function naturalSort(a, b){
// Replace select box with a text input box + autocomplete.
function replace_big_select_inputs(min_length) {
// To do replace, jQuery's autocomplete plugin must be loaded.
- if (typeof jQuery().autocomplete == "undefined")
+ if (!jQuery().autocomplete)
return;
// Set default for min_length.
@@ -174,10 +174,10 @@ function replace_big_select_inputs(min_l
text_input_elt.attr('id', select_elt.attr('id'));
text_input_elt.click( function() {
// Show all. Also provide note that load is happening since this can be slow.
- var cur_value = $(this).attr('value');
- $(this).attr('value', 'Loading...');
+ var cur_value = $(this).val();
+ $(this).val('Loading...');
$(this).showAllInCache();
- $(this).attr('value', cur_value);
+ $(this).val(cur_value);
$(this).select();
});
--- a/static/scripts/jquery.autocomplete.js
+++ b/static/scripts/jquery.autocomplete.js
@@ -17,819 +17,817 @@ String.prototype.endsWith = function(str
var return_key_pressed_for_autocomplete = false;
;(function($) {
-
+
$.fn.extend({
- autocomplete: function(urlOrData, options) {
- var isUrl = typeof urlOrData == "string";
- options = $.extend({}, $.Autocompleter.defaults, {
- url: isUrl ? urlOrData : null,
- data: isUrl ? null : urlOrData,
- delay: isUrl ? $.Autocompleter.defaults.delay : 10,
- max: options && !options.scroll ? 10 : 150
- }, options);
-
- // if highlight is set to false, replace it with a do-nothing function
- options.highlight = options.highlight || function(value) { return value; };
-
- // if the formatMatch option is not specified, then use formatItem for backwards compatibility
- options.formatMatch = options.formatMatch || options.formatItem;
-
- return this.each(function() {
- new $.Autocompleter(this, options);
- });
- },
- result: function(handler) {
- return this.bind("result", handler);
- },
- search: function(handler) {
- return this.trigger("search", [handler]);
- },
- flushCache: function() {
+ autocomplete: function(urlOrData, options) {
+ var isUrl = typeof urlOrData == "string";
+ options = $.extend({}, $.Autocompleter.defaults, {
+ url: isUrl ? urlOrData : null,
+ data: isUrl ? null : urlOrData,
+ delay: isUrl ? $.Autocompleter.defaults.delay : 10,
+ max: options && !options.scroll ? 10 : 150
+ }, options);
+
+ // if highlight is set to false, replace it with a do-nothing function
+ options.highlight = options.highlight || function(value) { return value; };
+
+ // if the formatMatch option is not specified, then use formatItem for backwards compatibility
+ options.formatMatch = options.formatMatch || options.formatItem;
+
+ return this.each(function() {
+ new $.Autocompleter(this, options);
+ });
+ },
+ result: function(handler) {
+ return this.bind("result", handler);
+ },
+ search: function(handler) {
+ return this.trigger("search", [handler]);
+ },
+ flushCache: function() {
return this.trigger("flushCache");
- },
- setOptions: function(options){
- return this.trigger("setOptions", [options]);
- },
- unautocomplete: function() {
- return this.trigger("unautocomplete");
- },
- // JG: add method to show all data in cache.
+ },
+ setOptions: function(options){
+ return this.trigger("setOptions", [options]);
+ },
+ unautocomplete: function() {
+ return this.trigger("unautocomplete");
+ },
+ // JG: add method to show all data in cache.
showAllInCache: function() {
- return this.trigger("showAllInCache");
- }
+ return this.trigger("showAllInCache");
+ }
});
$.Autocompleter = function(input, options) {
- var KEY = {
- UP: 38,
- DOWN: 40,
- DEL: 46,
- TAB: 9,
- RETURN: 13,
- ESC: 27,
- COMMA: 188,
- PAGEUP: 33,
- PAGEDOWN: 34,
- BACKSPACE: 8,
- COLON: 16
- };
+ var KEY = {
+ UP: 38,
+ DOWN: 40,
+ DEL: 46,
+ TAB: 9,
+ RETURN: 13,
+ ESC: 27,
+ COMMA: 188,
+ PAGEUP: 33,
+ PAGEDOWN: 34,
+ BACKSPACE: 8,
+ COLON: 16
+ };
- // Create $ object for input element
- var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
+ // Create $ object for input element
+ var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
- var timeout;
- var previousValue = "";
- var cache = $.Autocompleter.Cache(options);
- var hasFocus = 0;
- var lastKeyPressCode;
- var config = {
- mouseDownOnSelect: false
- };
- var select = $.Autocompleter.Select(options, input, selectCurrent, config);
-
- var blockSubmit;
-
- // prevent form submit in opera when selecting with return key
- $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
- if (blockSubmit) {
- blockSubmit = false;
- return false;
- }
- });
-
- // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
- $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
- // track last key pressed
- lastKeyPressCode = event.keyCode;
- switch(event.keyCode) {
-
- case KEY.UP:
- event.preventDefault();
- if ( select.visible() ) {
- select.prev();
- } else {
- onChange(0, true);
- }
- break;
-
- case KEY.DOWN:
- event.preventDefault();
- if ( select.visible() ) {
- select.next();
- } else {
- onChange(0, true);
- }
- break;
-
- case KEY.PAGEUP:
- event.preventDefault();
- if ( select.visible() ) {
- select.pageUp();
- } else {
- onChange(0, true);
- }
- break;
-
- case KEY.PAGEDOWN:
- event.preventDefault();
- if ( select.visible() ) {
- select.pageDown();
- } else {
- onChange(0, true);
- }
- break;
-
- // matches also semicolon
- case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
- case KEY.TAB:
- case KEY.RETURN:
- if (event.keyCode == KEY.RETURN)
- return_key_pressed_for_autocomplete = false;
- if( selectCurrent() ) {
- // stop default to prevent a form submit, Opera needs special handling
- event.preventDefault();
- blockSubmit = true;
-
- // JG: set flag to indicate that a selection just occurred using the return key. FYI:
- // event.stopPropagation() does not work.
- if (event.keyCode == KEY.RETURN)
- return_key_pressed_for_autocomplete = true;
-
- return false;
- }
-
- case KEY.ESC:
- select.hide();
- break;
- case KEY.COLON:
- break;
-
- default:
- clearTimeout(timeout);
- timeout = setTimeout(onChange, options.delay);
- break;
- }
- }).focus(function(){
- // track whether the field has focus, we shouldn't process any
- // results if the field no longer has focus
- hasFocus++;
- }).blur(function() {
- hasFocus = 0;
- if (!config.mouseDownOnSelect) {
- // JG: if blur and user is not selecting with mouse, hide
- // object.
- select.hide();
- }
- return this;
- }).click(function() {
- // show select when clicking in a focused field
- if ( hasFocus++ > 1 && !select.visible() ) {
- onChange(0, true);
- }
- return this;
- }).bind("search", function() {
- // TODO why not just specifying both arguments?
- var fn = (arguments.length > 1) ? arguments[1] : null;
- function findValueCallback(q, data) {
- var result;
- if( data && data.length ) {
- for (var i=0; i < data.length; i++) {
- if( data[i].result.toLowerCase() == q.toLowerCase() ) {
- result = data[i];
- break;
- }
- }
- }
- if( typeof fn == "function" ) fn(result);
- else $input.trigger("result", result && [result.data, result.value]);
- }
- $.each(trimWords($input.val()), function(i, value) {
- request(value, findValueCallback, findValueCallback);
- });
+ var timeout;
+ var previousValue = "";
+ var cache = $.Autocompleter.Cache(options);
+ var hasFocus = 0;
+ var lastKeyPressCode;
+ var config = {
+ mouseDownOnSelect: false
+ };
+ var select = $.Autocompleter.Select(options, input, selectCurrent, config);
+
+ var blockSubmit;
+
+ // prevent form submit in opera when selecting with return key
+ $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
+ if (blockSubmit) {
+ blockSubmit = false;
+ return false;
+ }
+ });
+
+ // Firefox only triggers holding down a key with keypress
+ $input.bind(($.browser.mozilla ? "keypress" : "keydown") + ".autocomplete", function(event) {
+ // track last key pressed
+ lastKeyPressCode = event.keyCode;
+ switch(event.keyCode) {
+
+ case KEY.UP:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.prev();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.DOWN:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.next();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.PAGEUP:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.pageUp();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.PAGEDOWN:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.pageDown();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ // matches also semicolon
+ case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
+ case KEY.TAB:
+ case KEY.RETURN:
+ if (event.keyCode == KEY.RETURN)
+ return_key_pressed_for_autocomplete = false;
+ if( selectCurrent() ) {
+ // stop default to prevent a form submit, Opera needs special handling
+ event.preventDefault();
+ blockSubmit = true;
+
+ // JG: set flag to indicate that a selection just occurred using the return key. FYI:
+ // event.stopPropagation() does not work.
+ if (event.keyCode == KEY.RETURN)
+ return_key_pressed_for_autocomplete = true;
+
+ return false;
+ }
+
+ case KEY.ESC:
+ select.hide();
+ break;
+ case KEY.COLON:
+ break;
+
+ default:
+ clearTimeout(timeout);
+ timeout = setTimeout(onChange, options.delay);
+ break;
+ }
+ }).focus(function(){
+ // track whether the field has focus, we shouldn't process any
+ // results if the field no longer has focus
+ hasFocus++;
+ }).blur(function() {
+ hasFocus = 0;
+ if (!config.mouseDownOnSelect) {
+ // JG: if blur and user is not selecting with mouse, hide
+ // object.
+ select.hide();
+ }
+ return this;
+ }).click(function() {
+ // show select when clicking in a focused field
+ if ( hasFocus++ > 1 && !select.visible() ) {
+ onChange(0, true);
+ }
+ return this;
+ }).bind("search", function() {
+ // TODO why not just specifying both arguments?
+ var fn = (arguments.length > 1) ? arguments[1] : null;
+ function findValueCallback(q, data) {
+ var result;
+ if( data && data.length ) {
+ for (var i=0; i < data.length; i++) {
+ if( data[i].result.toLowerCase() == q.toLowerCase() ) {
+ result = data[i];
+ break;
+ }
+ }
+ }
+ if( typeof fn == "function" ) fn(result);
+ else $input.trigger("result", result && [result.data, result.value]);
+ }
+ $.each(trimWords($input.val()), function(i, value) {
+ request(value, findValueCallback, findValueCallback);
+ });
- return this;
- }).bind("flushCache", function() {
- cache.flush();
- }).bind("setOptions", function() {
- $.extend(options, arguments[1]);
- // if we've updated the data, repopulate
- if ( "data" in arguments[1] )
- cache.populate();
- }).bind("unautocomplete", function() {
- select.unbind();
- $input.unbind();
- $(input.form).unbind(".autocomplete");
- })
- // JG: Show all data in cache.
- .bind("showAllInCache", function() {
- receiveData('', cache.load(''));
- });
-
-
- function selectCurrent() {
- var selected = select.selected();
- if( !selected )
- return false;
-
- var v = selected.result;
- previousValue = v;
-
- if ( options.multiple ) {
- var words = trimWords($input.val());
- if ( words.length > 1 ) {
- v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
- }
- v += options.multipleSeparator;
- }
-
- $input.val(v);
- hideResultsNow();
- $input.trigger("result", [selected.data, selected.value]);
- return true;
- }
-
- function onChange(crap, skipPrevCheck) {
- if( lastKeyPressCode == KEY.DEL ) {
- select.hide();
- return;
- }
+ return this;
+ }).bind("flushCache", function() {
+ cache.flush();
+ }).bind("setOptions", function() {
+ $.extend(options, arguments[1]);
+ // if we've updated the data, repopulate
+ if ( "data" in arguments[1] )
+ cache.populate();
+ }).bind("unautocomplete", function() {
+ select.unbind();
+ $input.unbind();
+ $(input.form).unbind(".autocomplete");
+ })
+ // JG: Show all data in cache.
+ .bind("showAllInCache", function() {
+ receiveData('', cache.load(''));
+ });
+
+ function selectCurrent() {
+ var selected = select.selected();
+ if( !selected )
+ return false;
+
+ var v = selected.result;
+ previousValue = v;
+
+ if ( options.multiple ) {
+ var words = trimWords($input.val());
+ if ( words.length > 1 ) {
+ v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
+ }
+ v += options.multipleSeparator;
+ }
+
+ $input.val(v);
+ hideResultsNow();
+ $input.trigger("result", [selected.data, selected.value]);
+ return true;
+ }
+
+ function onChange(crap, skipPrevCheck) {
+ if( lastKeyPressCode == KEY.DEL ) {
+ select.hide();
+ return;
+ }
- var currentValue = $input.val();
-
- if ( !skipPrevCheck && currentValue == previousValue )
- return;
-
- previousValue = currentValue;
-
- currentValue = lastWord(currentValue);
- if ( currentValue.length >= options.minChars) {
- $input.addClass(options.loadingClass);
- if (!options.matchCase)
- currentValue = currentValue.toLowerCase();
- request(currentValue, receiveData, hideResultsNow);
- } else {
- stopLoading();
- select.hide();
- }
- };
-
- function trimWords(value) {
- if ( !value ) {
- return [""];
- }
- var words = value.split( options.multipleSeparator );
- var result = [];
- $.each(words, function(i, value) {
- if ( $.trim(value) )
- result[i] = $.trim(value);
- });
- return result;
- }
-
- function lastWord(value) {
- if ( !options.multiple )
- return value;
- var words = trimWords(value);
- return words[words.length - 1];
- }
-
- // fills in the input box w/the first match (assumed to be the best match)
- // q: the term entered
- // sValue: the first matching result
- function autoFill(q, sValue){
- // autofill in the complete box w/the first match as long as the user hasn't entered in more data
- // if the last user key pressed was backspace, don't autofill
- if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
- // fill in the value (keep the case the user has typed)
- $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
- // select the portion of the value not typed by the user (so the next character will erase)
- $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
- }
- };
+ var currentValue = $input.val();
+
+ if ( !skipPrevCheck && currentValue == previousValue )
+ return;
+
+ previousValue = currentValue;
+
+ currentValue = lastWord(currentValue);
+ if ( currentValue.length >= options.minChars) {
+ $input.addClass(options.loadingClass);
+ if (!options.matchCase)
+ currentValue = currentValue.toLowerCase();
+ request(currentValue, receiveData, hideResultsNow);
+ } else {
+ stopLoading();
+ select.hide();
+ }
+ };
+
+ function trimWords(value) {
+ if ( !value ) {
+ return [""];
+ }
+ var words = value.split( options.multipleSeparator );
+ var result = [];
+ $.each(words, function(i, value) {
+ if ( $.trim(value) )
+ result[i] = $.trim(value);
+ });
+ return result;
+ }
+
+ function lastWord(value) {
+ if ( !options.multiple )
+ return value;
+ var words = trimWords(value);
+ return words[words.length - 1];
+ }
+
+ // fills in the input box w/the first match (assumed to be the best match)
+ // q: the term entered
+ // sValue: the first matching result
+ function autoFill(q, sValue){
+ // autofill in the complete box w/the first match as long as the user hasn't entered in more data
+ // if the last user key pressed was backspace, don't autofill
+ if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
+ // fill in the value (keep the case the user has typed)
+ $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
+ // select the portion of the value not typed by the user (so the next character will erase)
+ $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
+ }
+ };
- function hideResults() {
- clearTimeout(timeout);
- timeout = setTimeout(hideResultsNow, 200);
- };
+ function hideResults() {
+ clearTimeout(timeout);
+ timeout = setTimeout(hideResultsNow, 200);
+ };
- function hideResultsNow() {
- var wasVisible = select.visible();
- select.hide();
- clearTimeout(timeout);
- stopLoading();
- if (options.mustMatch) {
- // call search and run callback
- $input.search(
- function (result){
- // if no value found, clear the input box
- if( !result ) {
- if (options.multiple) {
- var words = trimWords($input.val()).slice(0, -1);
- $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
- }
- else
- $input.val( "" );
- }
- }
- );
- }
- if (wasVisible)
- // position cursor at end of input field
- $.Autocompleter.Selection(input, input.value.length, input.value.length);
- };
+ function hideResultsNow() {
+ var wasVisible = select.visible();
+ select.hide();
+ clearTimeout(timeout);
+ stopLoading();
+ if (options.mustMatch) {
+ // call search and run callback
+ $input.search(
+ function (result){
+ // if no value found, clear the input box
+ if( !result ) {
+ if (options.multiple) {
+ var words = trimWords($input.val()).slice(0, -1);
+ $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
+ }
+ else
+ $input.val( "" );
+ }
+ }
+ );
+ }
+ if (wasVisible)
+ // position cursor at end of input field
+ $.Autocompleter.Selection(input, input.value.length, input.value.length);
+ };
- function receiveData(q, data) {
- if ( data && data.length && hasFocus ) {
- stopLoading();
- select.display(data, q);
- autoFill(q, data[0].value);
- select.show();
- } else {
- hideResultsNow();
- }
- };
+ function receiveData(q, data) {
+ if ( data && data.length && hasFocus ) {
+ stopLoading();
+ select.display(data, q);
+ autoFill(q, data[0].value);
+ select.show();
+ } else {
+ hideResultsNow();
+ }
+ };
- function request(term, success, failure) {
- if (!options.matchCase)
- term = term.toLowerCase();
- var data = cache.load(term);
+ function request(term, success, failure) {
+ if (!options.matchCase)
+ term = term.toLowerCase();
+ var data = cache.load(term);
- // JG: hack: if term ends with ':', kill data to force an ajax request.
- if (term.endsWith(":"))
- data = null;
+ // JG: hack: if term ends with ':', kill data to force an ajax request.
+ if (term.endsWith(":"))
+ data = null;
- // recieve the cached data
- if (data && data.length) {
- success(term, data);
- // if an AJAX url has been supplied, try loading the data now
- } else if( (typeof options.url == "string") && (options.url.length > 0) ){
- var extraParams = {
- timestamp: +new Date()
- };
- $.each(options.extraParams, function(key, param) {
- extraParams[key] = typeof param == "function" ? param() : param;
- });
-
- $.ajax({
- // try to leverage ajaxQueue plugin to abort previous requests
- mode: "abort",
- // limit abortion to this input
- port: "autocomplete" + input.name,
- dataType: options.dataType,
- url: options.url,
- data: $.extend({
- q: lastWord(term),
- limit: options.max
- }, extraParams),
- success: function(data) {
- var parsed = options.parse && options.parse(data) || parse(data);
- cache.add(term, parsed);
- success(term, parsed);
- }
- });
- } else {
- // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
- select.emptyList();
- failure(term);
- }
- };
-
- function parse(data) {
- var parsed = [];
- var rows = data.split("\n");
- for (var i=0; i < rows.length; i++) {
- var row = $.trim(rows[i]);
- if (row) {
- row = row.split("|");
- parsed[parsed.length] = {
- data: row,
- value: row[0],
- result: options.formatResult && options.formatResult(row, row[0]) || row[0]
- };
- }
- }
- return parsed;
- };
+ // recieve the cached data
+ if (data && data.length) {
+ success(term, data);
+ // if an AJAX url has been supplied, try loading the data now
+ } else if( (typeof options.url == "string") && (options.url.length > 0) ){
+ var extraParams = {
+ timestamp: +new Date()
+ };
+ $.each(options.extraParams, function(key, param) {
+ extraParams[key] = typeof param == "function" ? param() : param;
+ });
+
+ $.ajax({
+ // try to leverage ajaxQueue plugin to abort previous requests
+ mode: "abort",
+ // limit abortion to this input
+ port: "autocomplete" + input.name,
+ dataType: options.dataType,
+ url: options.url,
+ data: $.extend({
+ q: lastWord(term),
+ limit: options.max
+ }, extraParams),
+ success: function(data) {
+ var parsed = options.parse && options.parse(data) || parse(data);
+ cache.add(term, parsed);
+ success(term, parsed);
+ }
+ });
+ } else {
+ // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
+ select.emptyList();
+ failure(term);
+ }
+ };
+
+ function parse(data) {
+ var parsed = [];
+ var rows = data.split("\n");
+ for (var i=0; i < rows.length; i++) {
+ var row = $.trim(rows[i]);
+ if (row) {
+ row = row.split("|");
+ parsed[parsed.length] = {
+ data: row,
+ value: row[0],
+ result: options.formatResult && options.formatResult(row, row[0]) || row[0]
+ };
+ }
+ }
+ return parsed;
+ };
- function stopLoading() {
- $input.removeClass(options.loadingClass);
- };
+ function stopLoading() {
+ $input.removeClass(options.loadingClass);
+ };
};
$.Autocompleter.defaults = {
- inputClass: "ac_input",
- resultsClass: "ac_results",
- loadingClass: "ac_loading",
- minChars: 1,
- delay: 400,
- matchCase: false,
- matchSubset: true,
- matchContains: false,
- cacheLength: 10,
- max: 100,
- mustMatch: false,
- extraParams: {},
- selectFirst: true,
- formatItem: function(row) { return row[0]; },
- formatMatch: null,
- autoFill: false,
- width: 0,
- multiple: false,
- multipleSeparator: ", ",
- highlight: function(value, term) {
- // JG: short-circuit highlighting if term is empty string.
- if (term == "")
- return value;
- return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
- },
+ inputClass: "ac_input",
+ resultsClass: "ac_results",
+ loadingClass: "ac_loading",
+ minChars: 1,
+ delay: 400,
+ matchCase: false,
+ matchSubset: true,
+ matchContains: false,
+ cacheLength: 10,
+ max: 100,
+ mustMatch: false,
+ extraParams: {},
+ selectFirst: true,
+ formatItem: function(row) { return row[0]; },
+ formatMatch: null,
+ autoFill: false,
+ width: 0,
+ multiple: false,
+ multipleSeparator: ", ",
+ highlight: function(value, term) {
+ // JG: short-circuit highlighting if term is empty string.
+ if (term == "")
+ return value;
+ return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
+ },
scroll: true,
scrollHeight: 180
};
$.Autocompleter.Cache = function(options) {
- var data = {};
- var length = 0;
+ var data = {};
+ var length = 0;
- function matchSubset(s, sub) {
- if (!options.matchCase)
- s = s.toLowerCase();
- var i = s.indexOf(sub);
- if (i == -1) return false;
- return i == 0 || options.matchContains;
- };
-
- function add(q, value) {
- if (length > options.cacheLength){
- flush();
- }
- if (!data[q]){
- length++;
- }
- data[q] = value;
- }
-
- function populate(){
- if( !options.data ) return false;
- // track the matches
- var stMatchSets = {},
- nullData = 0;
+ function matchSubset(s, sub) {
+ if (!options.matchCase)
+ s = s.toLowerCase();
+ var i = s.indexOf(sub);
+ if (i == -1) return false;
+ return i == 0 || options.matchContains;
+ };
+
+ function add(q, value) {
+ if (length > options.cacheLength){
+ flush();
+ }
+ if (!data[q]){
+ length++;
+ }
+ data[q] = value;
+ }
+
+ function populate(){
+ if( !options.data ) return false;
+ // track the matches
+ var stMatchSets = {},
+ nullData = 0;
- // no url was specified, we need to adjust the cache length to make sure it fits the local data store
- if( !options.url ) options.cacheLength = 1;
-
- // track all options for minChars = 0
- stMatchSets[""] = [];
-
- // loop through the array and create a lookup structure
- for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
- var rawValue = options.data[i];
- // if rawValue is a string, make an array otherwise just reference the array
- rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
-
- var value = options.formatMatch(rawValue, i+1, options.data.length);
- if ( value === false )
- continue;
-
- var firstChar = value.charAt(0).toLowerCase();
- // if no lookup array for this character exists, look it up now
- if( !stMatchSets[firstChar] )
- stMatchSets[firstChar] = [];
+ // no url was specified, we need to adjust the cache length to make sure it fits the local data store
+ if( !options.url ) options.cacheLength = 1;
+
+ // track all options for minChars = 0
+ stMatchSets[""] = [];
+
+ // loop through the array and create a lookup structure
+ for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
+ var rawValue = options.data[i];
+ // if rawValue is a string, make an array otherwise just reference the array
+ rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
+
+ var value = options.formatMatch(rawValue, i+1, options.data.length);
+ if ( value === false )
+ continue;
+
+ var firstChar = value.charAt(0).toLowerCase();
+ // if no lookup array for this character exists, look it up now
+ if( !stMatchSets[firstChar] )
+ stMatchSets[firstChar] = [];
- // if the match is a string
- var row = {
- value: value,
- data: rawValue,
- result: options.formatResult && options.formatResult(rawValue) || value
- };
-
- // push the current match into the set list
- stMatchSets[firstChar].push(row);
+ // if the match is a string
+ var row = {
+ value: value,
+ data: rawValue,
+ result: options.formatResult && options.formatResult(rawValue) || value
+ };
+
+ // push the current match into the set list
+ stMatchSets[firstChar].push(row);
- // keep track of minChars zero items
- if ( nullData++ < options.max ) {
- stMatchSets[""].push(row);
- }
- };
+ // keep track of minChars zero items
+ if ( nullData++ < options.max ) {
+ stMatchSets[""].push(row);
+ }
+ };
- // add the data items to the cache
- $.each(stMatchSets, function(i, value) {
- // increase the cache size
- options.cacheLength++;
- // add to the cache
- add(i, value);
- });
- }
-
- // populate any existing data
- setTimeout(populate, 25);
-
- function flush(){
- data = {};
- length = 0;
- }
-
- return {
- flush: flush,
- add: add,
- populate: populate,
- load: function(q) {
- if (!options.cacheLength || !length)
- return null;
+ // add the data items to the cache
+ $.each(stMatchSets, function(i, value) {
+ // increase the cache size
+ options.cacheLength++;
+ // add to the cache
+ add(i, value);
+ });
+ }
+
+ // populate any existing data
+ setTimeout(populate, 25);
+
+ function flush(){
+ data = {};
+ length = 0;
+ }
+
+ return {
+ flush: flush,
+ add: add,
+ populate: populate,
+ load: function(q) {
+ if (!options.cacheLength || !length)
+ return null;
- /*
- * if dealing w/local data and matchContains than we must make sure
- * to loop through all the data collections looking for matches
- */
- if( !options.url && options.matchContains ){
- // track all matches
- var csub = [];
- // loop through all the data grids for matches
- for( var k in data ){
- // don't search through the stMatchSets[""] (minChars: 0) cache
- // this prevents duplicates
- if( k.length > 0 ){
- var c = data[k];
- $.each(c, function(i, x) {
- // if we've got a match, add it to the array
- if (matchSubset(x.value, q)) {
- csub.push(x);
- }
- });
- }
- }
- return csub;
- } else
- // if the exact item exists, use it
- if (data[q]){
- return data[q];
- } else
- if (options.matchSubset) {
- for (var i = q.length - 1; i >= options.minChars; i--) {
- var c = data[q.substr(0, i)];
- if (c) {
- var csub = [];
- $.each(c, function(i, x) {
- if ( (x.data.indexOf("#Header") == 0) ||
- (matchSubset(x.value, q)) ) {
- csub[csub.length] = x;
- }
- });
- return csub;
- }
- }
+ /*
+ * if dealing w/local data and matchContains than we must make sure
+ * to loop through all the data collections looking for matches
+ */
+ if( !options.url && options.matchContains ) {
+ // track all matches
+ var csub = [];
+ // loop through all the data grids for matches
+ for( var k in data ) {
+ // don't search through the stMatchSets[""] (minChars: 0) cache
+ // this prevents duplicates
+ if( k.length > 0 ){
+ var c = data[k];
+ $.each(c, function(i, x) {
+ // if we've got a match, add it to the array
+ if (matchSubset(x.value, q)) {
+ csub.push(x);
+ }
+ });
+ }
+ }
+ return csub;
+ } else
+ // if the exact item exists, use it
+ if (data[q]) {
+ return data[q];
+ } else
+ if (options.matchSubset) {
+ for (var i = q.length - 1; i >= options.minChars; i--) {
+ var c = data[q.substr(0, i)];
+ if (c) {
+ var csub = [];
+ $.each(c, function(i, x) {
+ if ( (x.data.indexOf("#Header") == 0) ||
+ (matchSubset(x.value, q)) ) {
+ csub[csub.length] = x;
+ }
+ });
+ return csub;
+ }
+ }
- }
- return null;
- }
- };
+ }
+ return null;
+ }
+ };
};
$.Autocompleter.Select = function (options, input, select, config) {
- var CLASSES = {
- ACTIVE: "ac_over"
- };
-
- var listItems,
- active = -1,
- data,
- term = "",
- needsInit = true,
- element,
- list;
-
- // Create results
- function init() {
- if (!needsInit)
- return;
- element = $("<div/>")
- .hide()
- .addClass(options.resultsClass)
- .css("position", "absolute")
- .appendTo(document.body);
-
- list = $("<ul/>").appendTo(element).mouseover( function(event) {
- if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
- active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
- // JG: Only add active class if target is not a header.
- if (!headerAtPosition(active))
- $(target(event)).addClass(CLASSES.ACTIVE);
- }
- }).click(function(event) {
- // JG: Ignore click on header.
- active = $("li", list).index(target(event));
- if (headerAtPosition(active))
- return;
+ var CLASSES = {
+ ACTIVE: "ac_over"
+ };
+
+ var listItems,
+ active = -1,
+ data,
+ term = "",
+ needsInit = true,
+ element,
+ list;
+
+ // Create results
+ function init() {
+ if (!needsInit)
+ return;
+
+ element = $("<div/>")
+ .hide()
+ .addClass(options.resultsClass)
+ .css("position", "absolute")
+ .bind("mouseleave", function() {
+ element.hide();
+ })
+ .appendTo(document.body);
- // Handle click on autocomplete options.
- $(target(event)).addClass(CLASSES.ACTIVE);
- select();
- // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
- input.focus();
- return false;
- }).mousedown(function() {
- config.mouseDownOnSelect = true;
- }).mouseup(function() {
- config.mouseDownOnSelect = false;
- });
-
- if( options.width > 0 )
- element.css("width", options.width);
-
- needsInit = false;
- }
-
- function target(event) {
- var element = event.target;
- while(element && element.tagName != "LI")
- element = element.parentNode;
- // more fun with IE, sometimes event.target is empty, just ignore it then
- if(!element)
- return [];
- return element;
- }
+ list = $("<ul/>").appendTo(element).mouseover( function(event) {
+ if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
+ active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
+ // JG: Only add active class if target is not a header.
+ if (!headerAtPosition(active))
+ $(target(event)).addClass(CLASSES.ACTIVE);
+ }
+ }).click(function(event) {
+ // JG: Ignore click on header.
+ active = $("li", list).index(target(event));
+ if (headerAtPosition(active))
+ return;
- // JG: Returns true iff there is a header element at the given position.
- function headerAtPosition(position)
- {
- dataAtPosition = data[position].data;
- return (dataAtPosition[0].indexOf("#Header") == 0);
- }
+ // Handle click on autocomplete options.
+ $(target(event)).addClass(CLASSES.ACTIVE);
+ select();
+ // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
+ input.focus();
+ return false;
+ }).mousedown(function() {
+ config.mouseDownOnSelect = true;
+ }).mouseup(function() {
+ config.mouseDownOnSelect = false;
+ });
- function moveSelect(step) {
- listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
- // JG: while active item is a header, continue stepping.
- var isHeader = false;
- do
- {
- movePosition(step);
- isHeader = headerAtPosition(active);
- }
- while (isHeader);
- var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
+ if( options.width > 0 )
+ element.css("width", options.width);
+ needsInit = false;
+ }
+
+ function target(event) {
+ var element = event.target;
+ while(element && element.tagName != "LI")
+ element = element.parentNode;
+ // more fun with IE, sometimes event.target is empty, just ignore it then
+ if(!element)
+ return [];
+ return element;
+ }
+
+ // JG: Returns true iff there is a header element at the given position.
+ function headerAtPosition(position) {
+ dataAtPosition = data[position].data;
+ return (dataAtPosition[0].indexOf("#Header") == 0);
+ }
+
+ function moveSelect(step) {
+ listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
+ // JG: while active item is a header, continue stepping.
+ var isHeader = false;
+ do {
+ movePosition(step);
+ isHeader = headerAtPosition(active);
+ }
+ while (isHeader);
+ var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
if(options.scroll) {
var offset = 0;
listItems.slice(0, active).each(function() {
- offset += this.offsetHeight;
- });
+ offset += this.offsetHeight;
+ });
if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
} else if(offset < list.scrollTop()) {
list.scrollTop(offset);
}
}
- };
-
- function movePosition(step) {
- active += step;
- if (active < 0) {
- active = listItems.size() - 1;
- } else if (active >= listItems.size()) {
- active = 0;
- }
- }
-
- function limitNumberOfItems(available) {
- return options.max && options.max < available
- ? options.max
- : available;
- }
-
- function fillList() {
- list.empty();
- var max = limitNumberOfItems(data.length);
- for (var i=0; i < max; i++) {
- if (!data[i])
- continue;
- var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
- if ( formatted === false )
- continue;
+ };
+
+ function movePosition(step) {
+ active += step;
+ if (active < 0) {
+ active = listItems.size() - 1;
+ } else if (active >= listItems.size()) {
+ active = 0;
+ }
+ }
+
+ function limitNumberOfItems(available) {
+ return options.max && options.max < available
+ ? options.max
+ : available;
+ }
+
+ function fillList() {
+ list.empty();
+ var max = limitNumberOfItems(data.length);
+ for (var i=0; i < max; i++) {
+ if (!data[i])
+ continue;
+
+ var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
+ if ( formatted === false )
+ continue;
- // JG: Build list item by formatting the item and choosing a CSS class.
- if (headerAtPosition(i))
- {
- // Found header element; only add header if there are subsequent elements.
- if (i != max-1)
- var li = $("<li/>").html(data[i].data[1]).addClass("ac_header").appendTo(list)[0];
- }
- else
- {
- // Found completion element.
- var li = $("<li/>").html(options.highlight(formatted, term)).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
- }
+ // JG: Build list item by formatting the item and choosing a CSS class.
+ if (headerAtPosition(i)) {
+ // Found header element; only add header if there are subsequent elements.
+ if (i != max-1)
+ var li = $("<li/>").html(data[i].data[1]).addClass("ac_header").appendTo(list)[0];
+ } else {
+ // Found completion element.
+ var li = $("<li/>").html(options.highlight(formatted, term)).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
+ }
- $.data(li, "ac_data", data[i]);
- }
- listItems = list.find("li");
- if ( options.selectFirst ) {
- listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
- active = 0;
- }
- // apply bgiframe if available
- if ( $.fn.bgiframe )
- list.bgiframe();
- }
-
- return {
- display: function(d, q) {
- init();
- data = d;
- term = q;
- fillList();
- },
- next: function() {
- moveSelect(1);
- },
- prev: function() {
- moveSelect(-1);
- },
- pageUp: function() {
- if (active != 0 && active - 8 < 0) {
- moveSelect( -active );
- } else {
- moveSelect(-8);
- }
- },
- pageDown: function() {
- if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
- moveSelect( listItems.size() - 1 - active );
- } else {
- moveSelect(8);
- }
- },
- hide: function() {
- element && element.hide();
- listItems && listItems.removeClass(CLASSES.ACTIVE);
- active = -1;
- },
- visible : function() {
- return element && element.is(":visible");
- },
- current: function() {
- return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
- },
- show: function() {
- var offset = $(input).offset();
- element.css({
- width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
- top: offset.top + input.offsetHeight,
- left: offset.left
- }).show();
+ $.data(li, "ac_data", data[i]);
+ }
+ listItems = list.find("li");
+ if ( options.selectFirst ) {
+ listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
+ active = 0;
+ }
+ // apply bgiframe if available
+ if ( $.fn.bgiframe )
+ list.bgiframe();
+ }
+
+ return {
+ display: function(d, q) {
+ init();
+ data = d;
+ term = q;
+ fillList();
+ },
+ next: function() {
+ moveSelect(1);
+ },
+ prev: function() {
+ moveSelect(-1);
+ },
+ pageUp: function() {
+ if (active != 0 && active - 8 < 0) {
+ moveSelect( -active );
+ } else {
+ moveSelect(-8);
+ }
+ },
+ pageDown: function() {
+ if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
+ moveSelect( listItems.size() - 1 - active );
+ } else {
+ moveSelect(8);
+ }
+ },
+ hide: function() {
+ element && element.hide();
+ listItems && listItems.removeClass(CLASSES.ACTIVE);
+ active = -1;
+ },
+ visible : function() {
+ return element && element.is(":visible");
+ },
+ current: function() {
+ return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
+ },
+ show: function() {
+ var offset = $(input).offset();
+ element.css({
+ width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
+ top: offset.top + input.offsetHeight,
+ left: offset.left
+ }).show();
if(options.scroll) {
list.scrollTop(0);
list.css({
- maxHeight: options.scrollHeight,
- overflow: 'auto'
- });
-
+ maxHeight: options.scrollHeight,
+ overflow: 'auto'
+ });
+
if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
- var listHeight = 0;
- listItems.each(function() {
- listHeight += this.offsetHeight;
- });
- var scrollbarsVisible = listHeight > options.scrollHeight;
+ var listHeight = 0;
+ listItems.each(function() {
+ listHeight += this.offsetHeight;
+ });
+ var scrollbarsVisible = listHeight > options.scrollHeight;
list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
- if (!scrollbarsVisible) {
- // IE doesn't recalculate width when scrollbar disappears
- listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
- }
+ if (!scrollbarsVisible) {
+ // IE doesn't recalculate width when scrollbar disappears
+ listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
+ }
}
}
- },
- selected: function() {
- var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
- return selected && selected.length && $.data(selected[0], "ac_data");
- },
- emptyList: function (){
- list && list.empty();
- },
- unbind: function() {
- element && element.remove();
- }
- };
+ },
+ selected: function() {
+ var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
+ return selected && selected.length && $.data(selected[0], "ac_data");
+ },
+ emptyList: function (){
+ list && list.empty();
+ },
+ unbind: function() {
+ element && element.remove();
+ }
+ };
};
$.Autocompleter.Selection = function(field, start, end) {
- if( field.createTextRange ){
- var selRange = field.createTextRange();
- selRange.collapse(true);
- selRange.moveStart("character", start);
- selRange.moveEnd("character", end);
- selRange.select();
- } else if( field.setSelectionRange ){
- field.setSelectionRange(start, end);
- } else {
- if( field.selectionStart ){
- field.selectionStart = start;
- field.selectionEnd = end;
- }
- }
- field.focus();
+ if( field.createTextRange ){
+ var selRange = field.createTextRange();
+ selRange.collapse(true);
+ selRange.moveStart("character", start);
+ selRange.moveEnd("character", end);
+ selRange.select();
+ } else if( field.setSelectionRange ){
+ field.setSelectionRange(start, end);
+ } else {
+ if( field.selectionStart ){
+ field.selectionStart = start;
+ field.selectionEnd = end;
+ }
+ }
+ field.focus();
};
})(jQuery);
--- a/static/scripts/packed/galaxy.base.js
+++ b/static/scripts/packed/galaxy.base.js
@@ -1,1 +1,1 @@
-$(document).ready(function(){replace_big_select_inputs()});$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function ensure_popup_helper(){if($("#popup-helper").length===0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}function make_popupmenu
(c,b){ensure_popup_helper();var a=$("<ul id='"+c.attr("id")+"-menu'></ul>");$.each(b,function(f,e){if(e){$("<li/>").html(f).click(e).appendTo(a)}else{$("<li class='head'/>").html(f).appendTo(a)}});var d=$("<div class='popmenu-wrapper'>");d.append(a).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(c,d)}function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}else{if(e=="_top"){g=window.top}}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.addClass("popup").show()})}function array_length(b){if(b.length){return b.length}var c=0;for(var a in b){c++}return c}function naturalSort(i,g){var n=/(-?[0-9\.]+)/g,j=i.toString().toLowerCase()||"",f=g.toString().t
oLowerCase()||"",k=String.fromCharCode(0),l=j.replace(n,k+"$1"+k).split(k),e=f.replace(n,k+"$1"+k).split(k),d=(new Date(j)).getTime(),m=d?(new Date(f)).getTime():null;if(m){if(d<m){return -1}else{if(d>m){return 1}}}for(var h=0,c=Math.max(l.length,e.length);h<c;h++){oFxNcL=parseFloat(l[h])||l[h];oFyNcL=parseFloat(e[h])||e[h];if(oFxNcL<oFyNcL){return -1}else{if(oFxNcL>oFyNcL){return 1}}}return 0}function replace_big_select_inputs(a){if(typeof jQuery().autocomplete=="undefined"){return}if(a===undefined){a=20}$("select").each(function(){var d=$(this);if(d.find("option").length<a){return}if(d.attr("multiple")==true){return}var j=d.attr("value");var b=$("<input type='text' class='text-and-autocomplete-select'></input>");b.attr("size",40);b.attr("name",d.attr("name"));b.attr("id",d.attr("id"));b.click(function(){var k=$(this).attr("value");$(this).attr("value","Loading...");$(this).showAllInCache();$(this).attr("value",k);$(this).select()});var e=[];var g={};d.children("option").ea
ch(function(){var l=$(this).text();var k=$(this).attr("value");e.push(l);g[l]=k;g[k]=k;if(k==j){b.attr("value",l)}});if(j==""||j=="?"){b.attr("value","Click to Search or Select")}if(d.attr("name")=="dbkey"){e=e.sort(naturalSort)}var f={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:1000,minChars:0,hideForLessThanMinChars:false};b.autocomplete(e,f);d.replaceWith(b);var i=function(){var l=b.attr("value");var k=g[l];if(k!==null&&k!==undefined){b.attr("value",k)}else{if(j!=""){b.attr("value",j)}else{b.attr("value","?")}}};b.parents("form").submit(function(){i()});$(document).bind("convert_dbkeys",function(){i()});if(d.attr("refresh_on_change")=="true"){var c=d.attr("refresh_on_change_values");if(c!==undefined){c=c.split(",")}var h=function(){var m=b.attr("value");var l=g[m];if(l!==null&&l!==undefined){refresh=false;if(c!==undefined){for(var k=0;k<c.length;k++){if(l==c[k]){refresh=true;break}}}else{refresh=true}if(refresh){b.attr("value",l);b.parents("for
m").submit()}}};b.bind("result",h);b.keyup(function(k){if(k.keyCode===13){h()}});b.keydown(function(k){if(k.keyCode===13){return false}})}})}function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).live("click",function(){if($("#renaming-active").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text(k)}else{j=$("<input type='text'></input>").attr({value:k,size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){l.text(o);if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(d,a,c){var b=function(){try{var e=$.jStore.store("history_expand_state");i
f(e){for(var g in e){$("#"+g+" div.historyItemBody").show()}}}catch(f){$.jStore.remove("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}d.each(function(){var j=this.id;var h=$(this).children("div.historyItemBody");var i=h.find("pre.peek");$(this).find(".historyItemTitleBar > .historyItemTitle").wrap("<a href='javascript:void(0);'></a>").click(function(){if(h.is(":visible")){if($.browser.mozilla){i.css("overflow","hidden")}h.slideUp("fast");if(!c){var k=$.jStore.store("history_expand_state");if(k){delete k[j];$.jStore.store("history_expand_state",k)}}}else{h.slideDown("fast",function(){if($.browser.mozilla){i.css("overflow","auto")}});if(!c){var k=$.jStore.store("history_expand_state");if(k===undefined){k={}}k[j]=true;$.jStore.store("history_expand_state",k)}}return false})});$("#top-links > a.toggle").click(function(){var h=$.jStore.store("history_expand_sta
te");if(h===undefined){h={}}$("div.historyItemBody:visible").each(function(){if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(h){delete h[$(this).parent().attr("id")]}});$.jStore.store("history_expand_state",h)}).show()};if(a){b()}else{$.jStore.init("galaxy");$.jStore.engineReady(function(){b()})}}function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}$(document).ready(function(){$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tipsy){$(".tooltip").tipsy({gravity:"s"})}make_popup_menus()});
+$(document).ready(function(){replace_big_select_inputs()});$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function ensure_popup_helper(){if($("#popup-helper").length===0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}function make_popupmenu
(c,b){ensure_popup_helper();var a=$("<ul id='"+c.attr("id")+"-menu'></ul>");$.each(b,function(f,e){if(e){$("<li/>").html(f).click(e).appendTo(a)}else{$("<li class='head'/>").html(f).appendTo(a)}});var d=$("<div class='popmenu-wrapper'>");d.append(a).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(c,d)}function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}else{if(e=="_top"){g=window.top}}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.addClass("popup").show()})}function array_length(b){if(b.length){return b.length}var c=0;for(var a in b){c++}return c}function naturalSort(i,g){var n=/(-?[0-9\.]+)/g,j=i.toString().toLowerCase()||"",f=g.toString().t
oLowerCase()||"",k=String.fromCharCode(0),l=j.replace(n,k+"$1"+k).split(k),e=f.replace(n,k+"$1"+k).split(k),d=(new Date(j)).getTime(),m=d?(new Date(f)).getTime():null;if(m){if(d<m){return -1}else{if(d>m){return 1}}}for(var h=0,c=Math.max(l.length,e.length);h<c;h++){oFxNcL=parseFloat(l[h])||l[h];oFyNcL=parseFloat(e[h])||e[h];if(oFxNcL<oFyNcL){return -1}else{if(oFxNcL>oFyNcL){return 1}}}return 0}function replace_big_select_inputs(a){if(!jQuery().autocomplete){return}if(a===undefined){a=20}$("select").each(function(){var d=$(this);if(d.find("option").length<a){return}if(d.attr("multiple")==true){return}var j=d.attr("value");var b=$("<input type='text' class='text-and-autocomplete-select'></input>");b.attr("size",40);b.attr("name",d.attr("name"));b.attr("id",d.attr("id"));b.click(function(){var k=$(this).val();$(this).val("Loading...");$(this).showAllInCache();$(this).val(k);$(this).select()});var e=[];var g={};d.children("option").each(function(){var l=$(this).text();var k=$(th
is).attr("value");e.push(l);g[l]=k;g[k]=k;if(k==j){b.attr("value",l)}});if(j==""||j=="?"){b.attr("value","Click to Search or Select")}if(d.attr("name")=="dbkey"){e=e.sort(naturalSort)}var f={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:1000,minChars:0,hideForLessThanMinChars:false};b.autocomplete(e,f);d.replaceWith(b);var i=function(){var l=b.attr("value");var k=g[l];if(k!==null&&k!==undefined){b.attr("value",k)}else{if(j!=""){b.attr("value",j)}else{b.attr("value","?")}}};b.parents("form").submit(function(){i()});$(document).bind("convert_dbkeys",function(){i()});if(d.attr("refresh_on_change")=="true"){var c=d.attr("refresh_on_change_values");if(c!==undefined){c=c.split(",")}var h=function(){var m=b.attr("value");var l=g[m];if(l!==null&&l!==undefined){refresh=false;if(c!==undefined){for(var k=0;k<c.length;k++){if(l==c[k]){refresh=true;break}}}else{refresh=true}if(refresh){b.attr("value",l);b.parents("form").submit()}}};b.bind("result",h);b.keyup(fu
nction(k){if(k.keyCode===13){h()}});b.keydown(function(k){if(k.keyCode===13){return false}})}})}function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).live("click",function(){if($("#renaming-active").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text(k)}else{j=$("<input type='text'></input>").attr({value:k,size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){l.text(o);if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(d,a,c){var b=function(){try{var e=$.jStore.store("history_expand_state");if(e){for(var g in e){$("#"+g+" div.historyIte
mBody").show()}}}catch(f){$.jStore.remove("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}d.each(function(){var j=this.id;var h=$(this).children("div.historyItemBody");var i=h.find("pre.peek");$(this).find(".historyItemTitleBar > .historyItemTitle").wrap("<a href='javascript:void(0);'></a>").click(function(){if(h.is(":visible")){if($.browser.mozilla){i.css("overflow","hidden")}h.slideUp("fast");if(!c){var k=$.jStore.store("history_expand_state");if(k){delete k[j];$.jStore.store("history_expand_state",k)}}}else{h.slideDown("fast",function(){if($.browser.mozilla){i.css("overflow","auto")}});if(!c){var k=$.jStore.store("history_expand_state");if(k===undefined){k={}}k[j]=true;$.jStore.store("history_expand_state",k)}}return false})});$("#top-links > a.toggle").click(function(){var h=$.jStore.store("history_expand_state");if(h===undefined){h={}}$("div.historyIte
mBody:visible").each(function(){if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(h){delete h[$(this).parent().attr("id")]}});$.jStore.store("history_expand_state",h)}).show()};if(a){b()}else{$.jStore.init("galaxy");$.jStore.engineReady(function(){b()})}}function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}$(document).ready(function(){$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tipsy){$(".tooltip").tipsy({gravity:"s"})}make_popup_menus()});
--- a/static/scripts/packed/jquery.autocomplete.js
+++ b/static/scripts/packed/jquery.autocomplete.js
@@ -1,1 +1,1 @@
-String.prototype.endsWith=function(a){return(this.match(a+"$")==a)};var return_key_pressed_for_autocomplete=false;(function(a){a.fn.extend({autocomplete:function(b,c){var d=typeof b=="string";c=a.extend({},a.Autocompleter.defaults,{url:d?b:null,data:d?null:b,delay:d?a.Autocompleter.defaults.delay:10,max:c&&!c.scroll?10:150},c);c.highlight=c.highlight||function(e){return e};c.formatMatch=c.formatMatch||c.formatItem;return this.each(function(){new a.Autocompleter(this,c)})},result:function(b){return this.bind("result",b)},search:function(b){return this.trigger("search",[b])},flushCache:function(){return this.trigger("flushCache")},setOptions:function(b){return this.trigger("setOptions",[b])},unautocomplete:function(){return this.trigger("unautocomplete")},showAllInCache:function(){return this.trigger("showAllInCache")}});a.Autocompleter=function(l,g){var c={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8,COLON:16};var b=a(l).attr("autoco
mplete","off").addClass(g.inputClass);var j;var p="";var m=a.Autocompleter.Cache(g);var e=0;var u;var x={mouseDownOnSelect:false};var r=a.Autocompleter.Select(g,l,d,x);var w;a.browser.opera&&a(l.form).bind("submit.autocomplete",function(){if(w){w=false;return false}});b.bind((a.browser.opera?"keypress":"keydown")+".autocomplete",function(y){u=y.keyCode;switch(y.keyCode){case c.UP:y.preventDefault();if(r.visible()){r.prev()}else{t(0,true)}break;case c.DOWN:y.preventDefault();if(r.visible()){r.next()}else{t(0,true)}break;case c.PAGEUP:y.preventDefault();if(r.visible()){r.pageUp()}else{t(0,true)}break;case c.PAGEDOWN:y.preventDefault();if(r.visible()){r.pageDown()}else{t(0,true)}break;case g.multiple&&a.trim(g.multipleSeparator)==","&&c.COMMA:case c.TAB:case c.RETURN:if(y.keyCode==c.RETURN){return_key_pressed_for_autocomplete=false}if(d()){y.preventDefault();w=true;if(y.keyCode==c.RETURN){return_key_pressed_for_autocomplete=true}return false}case c.ESC:r.hide();break;case c.COL
ON:break;default:clearTimeout(j);j=setTimeout(t,g.delay);break}}).focus(function(){e++}).blur(function(){e=0;if(!x.mouseDownOnSelect){r.hide()}return this}).click(function(){if(e++>1&&!r.visible()){t(0,true)}return this}).bind("search",function(){var y=(arguments.length>1)?arguments[1]:null;function z(D,C){var A;if(C&&C.length){for(var B=0;B<C.length;B++){if(C[B].result.toLowerCase()==D.toLowerCase()){A=C[B];break}}}if(typeof y=="function"){y(A)}else{b.trigger("result",A&&[A.data,A.value])}}a.each(h(b.val()),function(A,B){f(B,z,z)});return this}).bind("flushCache",function(){m.flush()}).bind("setOptions",function(){a.extend(g,arguments[1]);if("data" in arguments[1]){m.populate()}}).bind("unautocomplete",function(){r.unbind();b.unbind();a(l.form).unbind(".autocomplete")}).bind("showAllInCache",function(){k("",m.load(""))});function d(){var z=r.selected();if(!z){return false}var y=z.result;p=y;if(g.multiple){var A=h(b.val());if(A.length>1){y=A.slice(0,A.length-1).join(g.multip
leSeparator)+g.multipleSeparator+y}y+=g.multipleSeparator}b.val(y);v();b.trigger("result",[z.data,z.value]);return true}function t(A,z){if(u==c.DEL){r.hide();return}var y=b.val();if(!z&&y==p){return}p=y;y=i(y);if(y.length>=g.minChars){b.addClass(g.loadingClass);if(!g.matchCase){y=y.toLowerCase()}f(y,k,v)}else{n();r.hide()}}function h(z){if(!z){return[""]}var A=z.split(g.multipleSeparator);var y=[];a.each(A,function(B,C){if(a.trim(C)){y[B]=a.trim(C)}});return y}function i(y){if(!g.multiple){return y}var z=h(y);return z[z.length-1]}function q(y,z){if(g.autoFill&&(i(b.val()).toLowerCase()==y.toLowerCase())&&u!=c.BACKSPACE){b.val(b.val()+z.substring(i(p).length));a.Autocompleter.Selection(l,p.length,p.length+z.length)}}function s(){clearTimeout(j);j=setTimeout(v,200)}function v(){var y=r.visible();r.hide();clearTimeout(j);n();if(g.mustMatch){b.search(function(z){if(!z){if(g.multiple){var A=h(b.val()).slice(0,-1);b.val(A.join(g.multipleSeparator)+(A.length?g.multipleSeparator:"")
)}else{b.val("")}}})}if(y){a.Autocompleter.Selection(l,l.value.length,l.value.length)}}function k(z,y){if(y&&y.length&&e){n();r.display(y,z);q(z,y[0].value);r.show()}else{v()}}function f(z,B,y){if(!g.matchCase){z=z.toLowerCase()}var A=m.load(z);if(z.endsWith(":")){A=null}if(A&&A.length){B(z,A)}else{if((typeof g.url=="string")&&(g.url.length>0)){var C={timestamp:+new Date()};a.each(g.extraParams,function(D,E){C[D]=typeof E=="function"?E():E});a.ajax({mode:"abort",port:"autocomplete"+l.name,dataType:g.dataType,url:g.url,data:a.extend({q:i(z),limit:g.max},C),success:function(E){var D=g.parse&&g.parse(E)||o(E);m.add(z,D);B(z,D)}})}else{r.emptyList();y(z)}}}function o(B){var y=[];var A=B.split("\n");for(var z=0;z<A.length;z++){var C=a.trim(A[z]);if(C){C=C.split("|");y[y.length]={data:C,value:C[0],result:g.formatResult&&g.formatResult(C,C[0])||C[0]}}}return y}function n(){b.removeClass(g.loadingClass)}};a.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",load
ingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(b){return b[0]},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(c,b){if(b==""){return c}return c.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+b.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>")},scroll:true,scrollHeight:180};a.Autocompleter.Cache=function(c){var f={};var d=0;function h(l,k){if(!c.matchCase){l=l.toLowerCase()}var j=l.indexOf(k);if(j==-1){return false}return j==0||c.matchContains}function g(j,i){if(d>c.cacheLength){b()}if(!f[j]){d++}f[j]=i}function e(){if(!c.data){return false}var k={},j=0;if(!c.url){c.cacheLength=1}k[""]=[];for(var m=0,l=c.data.length;m<l;m++){var p=c.data[m];p=(typeof p=="string")?[p]:p;var o=c.formatMatch(p,m+1,c.data.length);if(o===false){continue}var
n=o.charAt(0).toLowerCase();if(!k[n]){k[n]=[]}var q={value:o,data:p,result:c.formatResult&&c.formatResult(p)||o};k[n].push(q);if(j++<c.max){k[""].push(q)}}a.each(k,function(r,s){c.cacheLength++;g(r,s)})}setTimeout(e,25);function b(){f={};d=0}return{flush:b,add:g,populate:e,load:function(n){if(!c.cacheLength||!d){return null}if(!c.url&&c.matchContains){var m=[];for(var j in f){if(j.length>0){var o=f[j];a.each(o,function(p,k){if(h(k.value,n)){m.push(k)}})}}return m}else{if(f[n]){return f[n]}else{if(c.matchSubset){for(var l=n.length-1;l>=c.minChars;l--){var o=f[n.substr(0,l)];if(o){var m=[];a.each(o,function(p,k){if((k.data.indexOf("#Header")==0)||(h(k.value,n))){m[m.length]=k}});return m}}}}}return null}}};a.Autocompleter.Select=function(e,j,l,q){var i={ACTIVE:"ac_over"};var k,f=-1,s,m="",t=true,c,p;function o(){if(!t){return}c=a("<div/>").hide().addClass(e.resultsClass).css("position","absolute").appendTo(document.body);p=a("<ul/>").appendTo(c).mouseover(function(u){if(r(u).
nodeName&&r(u).nodeName.toUpperCase()=="LI"){f=a("li",p).removeClass(i.ACTIVE).index(r(u));if(!n(f)){a(r(u)).addClass(i.ACTIVE)}}}).click(function(u){f=a("li",p).index(r(u));if(n(f)){return}a(r(u)).addClass(i.ACTIVE);l();j.focus();return false}).mousedown(function(){q.mouseDownOnSelect=true}).mouseup(function(){q.mouseDownOnSelect=false});if(e.width>0){c.css("width",e.width)}t=false}function r(v){var u=v.target;while(u&&u.tagName!="LI"){u=u.parentNode}if(!u){return[]}return u}function n(u){dataAtPosition=s[u].data;return(dataAtPosition[0].indexOf("#Header")==0)}function h(u){k.slice(f,f+1).removeClass(i.ACTIVE);var v=false;do{g(u);v=n(f)}while(v);var x=k.slice(f,f+1).addClass(i.ACTIVE);if(e.scroll){var w=0;k.slice(0,f).each(function(){w+=this.offsetHeight});if((w+x[0].offsetHeight-p.scrollTop())>p[0].clientHeight){p.scrollTop(w+x[0].offsetHeight-p.innerHeight())}else{if(w<p.scrollTop()){p.scrollTop(w)}}}}function g(u){f+=u;if(f<0){f=k.size()-1}else{if(f>=k.size()){f=0}}}func
tion b(u){return e.max&&e.max<u?e.max:u}function d(){p.empty();var v=b(s.length);for(var w=0;w<v;w++){if(!s[w]){continue}var x=e.formatItem(s[w].data,w+1,v,s[w].value,m);if(x===false){continue}if(n(w)){if(w!=v-1){var u=a("<li/>").html(s[w].data[1]).addClass("ac_header").appendTo(p)[0]}}else{var u=a("<li/>").html(e.highlight(x,m)).addClass(w%2==0?"ac_even":"ac_odd").appendTo(p)[0]}a.data(u,"ac_data",s[w])}k=p.find("li");if(e.selectFirst){k.slice(0,1).addClass(i.ACTIVE);f=0}if(a.fn.bgiframe){p.bgiframe()}}return{display:function(v,u){o();s=v;m=u;d()},next:function(){h(1)},prev:function(){h(-1)},pageUp:function(){if(f!=0&&f-8<0){h(-f)}else{h(-8)}},pageDown:function(){if(f!=k.size()-1&&f+8>k.size()){h(k.size()-1-f)}else{h(8)}},hide:function(){c&&c.hide();k&&k.removeClass(i.ACTIVE);f=-1},visible:function(){return c&&c.is(":visible")},current:function(){return this.visible()&&(k.filter("."+i.ACTIVE)[0]||e.selectFirst&&k[0])},show:function(){var w=a(j).offset();c.css({width:typeof
e.width=="string"||e.width>0?e.width:a(j).width(),top:w.top+j.offsetHeight,left:w.left}).show();if(e.scroll){p.scrollTop(0);p.css({maxHeight:e.scrollHeight,overflow:"auto"});if(a.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var u=0;k.each(function(){u+=this.offsetHeight});var v=u>e.scrollHeight;p.css("height",v?e.scrollHeight:u);if(!v){k.width(p.width()-parseInt(k.css("padding-left"))-parseInt(k.css("padding-right")))}}}},selected:function(){var u=k&&k.filter("."+i.ACTIVE).removeClass(i.ACTIVE);return u&&u.length&&a.data(u[0],"ac_data")},emptyList:function(){p&&p.empty()},unbind:function(){c&&c.remove()}}};a.Autocompleter.Selection=function(d,e,c){if(d.createTextRange){var b=d.createTextRange();b.collapse(true);b.moveStart("character",e);b.moveEnd("character",c);b.select()}else{if(d.setSelectionRange){d.setSelectionRange(e,c)}else{if(d.selectionStart){d.selectionStart=e;d.selectionEnd=c}}}d.focus()}})(jQuery);
+String.prototype.endsWith=function(a){return(this.match(a+"$")==a)};var return_key_pressed_for_autocomplete=false;(function(a){a.fn.extend({autocomplete:function(b,c){var d=typeof b=="string";c=a.extend({},a.Autocompleter.defaults,{url:d?b:null,data:d?null:b,delay:d?a.Autocompleter.defaults.delay:10,max:c&&!c.scroll?10:150},c);c.highlight=c.highlight||function(e){return e};c.formatMatch=c.formatMatch||c.formatItem;return this.each(function(){new a.Autocompleter(this,c)})},result:function(b){return this.bind("result",b)},search:function(b){return this.trigger("search",[b])},flushCache:function(){return this.trigger("flushCache")},setOptions:function(b){return this.trigger("setOptions",[b])},unautocomplete:function(){return this.trigger("unautocomplete")},showAllInCache:function(){return this.trigger("showAllInCache")}});a.Autocompleter=function(l,g){var c={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8,COLON:16};var b=a(l).attr("autoco
mplete","off").addClass(g.inputClass);var j;var p="";var m=a.Autocompleter.Cache(g);var e=0;var u;var x={mouseDownOnSelect:false};var r=a.Autocompleter.Select(g,l,d,x);var w;a.browser.opera&&a(l.form).bind("submit.autocomplete",function(){if(w){w=false;return false}});b.bind((a.browser.mozilla?"keypress":"keydown")+".autocomplete",function(y){u=y.keyCode;switch(y.keyCode){case c.UP:y.preventDefault();if(r.visible()){r.prev()}else{t(0,true)}break;case c.DOWN:y.preventDefault();if(r.visible()){r.next()}else{t(0,true)}break;case c.PAGEUP:y.preventDefault();if(r.visible()){r.pageUp()}else{t(0,true)}break;case c.PAGEDOWN:y.preventDefault();if(r.visible()){r.pageDown()}else{t(0,true)}break;case g.multiple&&a.trim(g.multipleSeparator)==","&&c.COMMA:case c.TAB:case c.RETURN:if(y.keyCode==c.RETURN){return_key_pressed_for_autocomplete=false}if(d()){y.preventDefault();w=true;if(y.keyCode==c.RETURN){return_key_pressed_for_autocomplete=true}return false}case c.ESC:r.hide();break;case c.C
OLON:break;default:clearTimeout(j);j=setTimeout(t,g.delay);break}}).focus(function(){e++}).blur(function(){e=0;if(!x.mouseDownOnSelect){r.hide()}return this}).click(function(){if(e++>1&&!r.visible()){t(0,true)}return this}).bind("search",function(){var y=(arguments.length>1)?arguments[1]:null;function z(D,C){var A;if(C&&C.length){for(var B=0;B<C.length;B++){if(C[B].result.toLowerCase()==D.toLowerCase()){A=C[B];break}}}if(typeof y=="function"){y(A)}else{b.trigger("result",A&&[A.data,A.value])}}a.each(h(b.val()),function(A,B){f(B,z,z)});return this}).bind("flushCache",function(){m.flush()}).bind("setOptions",function(){a.extend(g,arguments[1]);if("data" in arguments[1]){m.populate()}}).bind("unautocomplete",function(){r.unbind();b.unbind();a(l.form).unbind(".autocomplete")}).bind("showAllInCache",function(){k("",m.load(""))});function d(){var z=r.selected();if(!z){return false}var y=z.result;p=y;if(g.multiple){var A=h(b.val());if(A.length>1){y=A.slice(0,A.length-1).join(g.mult
ipleSeparator)+g.multipleSeparator+y}y+=g.multipleSeparator}b.val(y);v();b.trigger("result",[z.data,z.value]);return true}function t(A,z){if(u==c.DEL){r.hide();return}var y=b.val();if(!z&&y==p){return}p=y;y=i(y);if(y.length>=g.minChars){b.addClass(g.loadingClass);if(!g.matchCase){y=y.toLowerCase()}f(y,k,v)}else{n();r.hide()}}function h(z){if(!z){return[""]}var A=z.split(g.multipleSeparator);var y=[];a.each(A,function(B,C){if(a.trim(C)){y[B]=a.trim(C)}});return y}function i(y){if(!g.multiple){return y}var z=h(y);return z[z.length-1]}function q(y,z){if(g.autoFill&&(i(b.val()).toLowerCase()==y.toLowerCase())&&u!=c.BACKSPACE){b.val(b.val()+z.substring(i(p).length));a.Autocompleter.Selection(l,p.length,p.length+z.length)}}function s(){clearTimeout(j);j=setTimeout(v,200)}function v(){var y=r.visible();r.hide();clearTimeout(j);n();if(g.mustMatch){b.search(function(z){if(!z){if(g.multiple){var A=h(b.val()).slice(0,-1);b.val(A.join(g.multipleSeparator)+(A.length?g.multipleSeparator:"
"))}else{b.val("")}}})}if(y){a.Autocompleter.Selection(l,l.value.length,l.value.length)}}function k(z,y){if(y&&y.length&&e){n();r.display(y,z);q(z,y[0].value);r.show()}else{v()}}function f(z,B,y){if(!g.matchCase){z=z.toLowerCase()}var A=m.load(z);if(z.endsWith(":")){A=null}if(A&&A.length){B(z,A)}else{if((typeof g.url=="string")&&(g.url.length>0)){var C={timestamp:+new Date()};a.each(g.extraParams,function(D,E){C[D]=typeof E=="function"?E():E});a.ajax({mode:"abort",port:"autocomplete"+l.name,dataType:g.dataType,url:g.url,data:a.extend({q:i(z),limit:g.max},C),success:function(E){var D=g.parse&&g.parse(E)||o(E);m.add(z,D);B(z,D)}})}else{r.emptyList();y(z)}}}function o(B){var y=[];var A=B.split("\n");for(var z=0;z<A.length;z++){var C=a.trim(A[z]);if(C){C=C.split("|");y[y.length]={data:C,value:C[0],result:g.formatResult&&g.formatResult(C,C[0])||C[0]}}}return y}function n(){b.removeClass(g.loadingClass)}};a.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",lo
adingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(b){return b[0]},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(c,b){if(b==""){return c}return c.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+b.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>")},scroll:true,scrollHeight:180};a.Autocompleter.Cache=function(c){var f={};var d=0;function h(l,k){if(!c.matchCase){l=l.toLowerCase()}var j=l.indexOf(k);if(j==-1){return false}return j==0||c.matchContains}function g(j,i){if(d>c.cacheLength){b()}if(!f[j]){d++}f[j]=i}function e(){if(!c.data){return false}var k={},j=0;if(!c.url){c.cacheLength=1}k[""]=[];for(var m=0,l=c.data.length;m<l;m++){var p=c.data[m];p=(typeof p=="string")?[p]:p;var o=c.formatMatch(p,m+1,c.data.length);if(o===false){continue}v
ar n=o.charAt(0).toLowerCase();if(!k[n]){k[n]=[]}var q={value:o,data:p,result:c.formatResult&&c.formatResult(p)||o};k[n].push(q);if(j++<c.max){k[""].push(q)}}a.each(k,function(r,s){c.cacheLength++;g(r,s)})}setTimeout(e,25);function b(){f={};d=0}return{flush:b,add:g,populate:e,load:function(n){if(!c.cacheLength||!d){return null}if(!c.url&&c.matchContains){var m=[];for(var j in f){if(j.length>0){var o=f[j];a.each(o,function(p,k){if(h(k.value,n)){m.push(k)}})}}return m}else{if(f[n]){return f[n]}else{if(c.matchSubset){for(var l=n.length-1;l>=c.minChars;l--){var o=f[n.substr(0,l)];if(o){var m=[];a.each(o,function(p,k){if((k.data.indexOf("#Header")==0)||(h(k.value,n))){m[m.length]=k}});return m}}}}}return null}}};a.Autocompleter.Select=function(e,j,l,q){var i={ACTIVE:"ac_over"};var k,f=-1,s,m="",t=true,c,p;function o(){if(!t){return}c=a("<div/>").hide().addClass(e.resultsClass).css("position","absolute").bind("mouseleave",function(){c.hide()}).appendTo(document.body);p=a("<ul/>").
appendTo(c).mouseover(function(u){if(r(u).nodeName&&r(u).nodeName.toUpperCase()=="LI"){f=a("li",p).removeClass(i.ACTIVE).index(r(u));if(!n(f)){a(r(u)).addClass(i.ACTIVE)}}}).click(function(u){f=a("li",p).index(r(u));if(n(f)){return}a(r(u)).addClass(i.ACTIVE);l();j.focus();return false}).mousedown(function(){q.mouseDownOnSelect=true}).mouseup(function(){q.mouseDownOnSelect=false});if(e.width>0){c.css("width",e.width)}t=false}function r(v){var u=v.target;while(u&&u.tagName!="LI"){u=u.parentNode}if(!u){return[]}return u}function n(u){dataAtPosition=s[u].data;return(dataAtPosition[0].indexOf("#Header")==0)}function h(u){k.slice(f,f+1).removeClass(i.ACTIVE);var v=false;do{g(u);v=n(f)}while(v);var x=k.slice(f,f+1).addClass(i.ACTIVE);if(e.scroll){var w=0;k.slice(0,f).each(function(){w+=this.offsetHeight});if((w+x[0].offsetHeight-p.scrollTop())>p[0].clientHeight){p.scrollTop(w+x[0].offsetHeight-p.innerHeight())}else{if(w<p.scrollTop()){p.scrollTop(w)}}}}function g(u){f+=u;if(f<0){f=
k.size()-1}else{if(f>=k.size()){f=0}}}function b(u){return e.max&&e.max<u?e.max:u}function d(){p.empty();var v=b(s.length);for(var w=0;w<v;w++){if(!s[w]){continue}var x=e.formatItem(s[w].data,w+1,v,s[w].value,m);if(x===false){continue}if(n(w)){if(w!=v-1){var u=a("<li/>").html(s[w].data[1]).addClass("ac_header").appendTo(p)[0]}}else{var u=a("<li/>").html(e.highlight(x,m)).addClass(w%2==0?"ac_even":"ac_odd").appendTo(p)[0]}a.data(u,"ac_data",s[w])}k=p.find("li");if(e.selectFirst){k.slice(0,1).addClass(i.ACTIVE);f=0}if(a.fn.bgiframe){p.bgiframe()}}return{display:function(v,u){o();s=v;m=u;d()},next:function(){h(1)},prev:function(){h(-1)},pageUp:function(){if(f!=0&&f-8<0){h(-f)}else{h(-8)}},pageDown:function(){if(f!=k.size()-1&&f+8>k.size()){h(k.size()-1-f)}else{h(8)}},hide:function(){c&&c.hide();k&&k.removeClass(i.ACTIVE);f=-1},visible:function(){return c&&c.is(":visible")},current:function(){return this.visible()&&(k.filter("."+i.ACTIVE)[0]||e.selectFirst&&k[0])},show:function(
){var w=a(j).offset();c.css({width:typeof e.width=="string"||e.width>0?e.width:a(j).width(),top:w.top+j.offsetHeight,left:w.left}).show();if(e.scroll){p.scrollTop(0);p.css({maxHeight:e.scrollHeight,overflow:"auto"});if(a.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var u=0;k.each(function(){u+=this.offsetHeight});var v=u>e.scrollHeight;p.css("height",v?e.scrollHeight:u);if(!v){k.width(p.width()-parseInt(k.css("padding-left"))-parseInt(k.css("padding-right")))}}}},selected:function(){var u=k&&k.filter("."+i.ACTIVE).removeClass(i.ACTIVE);return u&&u.length&&a.data(u[0],"ac_data")},emptyList:function(){p&&p.empty()},unbind:function(){c&&c.remove()}}};a.Autocompleter.Selection=function(d,e,c){if(d.createTextRange){var b=d.createTextRange();b.collapse(true);b.moveStart("character",e);b.moveEnd("character",c);b.select()}else{if(d.setSelectionRange){d.setSelectionRange(e,c)}else{if(d.selectionStart){d.selectionStart=e;d.selectionEnd=c}}}d.focus()}})(jQuery);
1
0
galaxy-dist commit 4fb747f317d0: When using gzip compression in the upstream proxy, do not gzip compress library tar.gz or zip archives. bz2 then remains as the only compression perfomed in Galaxy itself.
by commits-noreply@bitbucket.org 07 Jun '10
by commits-noreply@bitbucket.org 07 Jun '10
07 Jun '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1275924249 14400
# Node ID 4fb747f317d0b2c36ffb5fbf4b815caf4cb6ace1
# Parent 48ec25db21c3bd76b52bcd68a1301f777eea280e
When using gzip compression in the upstream proxy, do not gzip compress library tar.gz or zip archives. bz2 then remains as the only compression perfomed in Galaxy itself.
--- a/templates/library/common/common.mako
+++ b/templates/library/common/common.mako
@@ -382,15 +382,15 @@
# This condition should not contain an else clause because the user is not authorized
# to manage dataset permissions unless the default action is 'manage_permissions'
%endif
- %if 'bz2' in comptypes:
- <option value="tbz"
+ %if 'gz' in comptypes:
+ <option value="tgz"
%if default_action == 'download':
selected
%endif>
- >Download as a .tar.bz2 file</option>
+ >Download as a .tar.gz file</option>
%endif
- %if 'gz' in comptypes:
- <option value="tgz">Download as a .tar.gz file</option>
+ %if 'bz2' in comptypes:
+ <option value="tbz">Download as a .tar.bz2 file</option>
%endif
%if 'zip' in comptypes:
<option value="zip">Download as a .zip file</option>
--- a/lib/galaxy/web/controllers/library_common.py
+++ b/lib/galaxy/web/controllers/library_common.py
@@ -1364,14 +1364,22 @@ class LibraryCommon( BaseController ):
# Can't use mkstemp - the file must not exist first
tmpd = tempfile.mkdtemp()
tmpf = os.path.join( tmpd, 'library_download.' + action )
- if ziptype == '64':
+ if ziptype == '64' and trans.app.config.upstream_gzip:
+ archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_STORED, True )
+ elif ziptype == '64':
archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True )
+ elif trans.app.config.upstream_gzip:
+ archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_STORED )
else:
archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED )
archive.add = lambda x, y: archive.write( x, y.encode('CP437') )
elif action == 'tgz':
- archive = util.streamball.StreamBall( 'w|gz' )
- outext = 'tgz'
+ if trans.app.config.upstream_gzip:
+ archive = util.streamball.StreamBall( 'w' )
+ outext = 'tar'
+ else:
+ archive = util.streamball.StreamBall( 'w|gz' )
+ outext = 'tgz'
elif action == 'tbz':
archive = util.streamball.StreamBall( 'w|bz2' )
outext = 'tbz2'
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -99,6 +99,7 @@ class Configuration( object ):
raise ConfigurationError( "user_library_import_dir specified in config (%s) does not exist" % self.user_library_import_dir )
self.allow_library_path_paste = kwargs.get( 'allow_library_path_paste', False )
# Configuration options for taking advantage of nginx features
+ self.upstream_gzip = string_as_bool( kwargs.get( 'upstream_gzip', False ) )
self.apache_xsendfile = kwargs.get( 'apache_xsendfile', False )
self.nginx_x_accel_redirect_base = kwargs.get( 'nginx_x_accel_redirect_base', False )
self.nginx_x_archive_files_base = kwargs.get( 'nginx_x_archive_files_base', False )
--- a/templates/library/common/browse_library.mako
+++ b/templates/library/common/browse_library.mako
@@ -507,12 +507,16 @@
TIP: Multiple compression options are available for downloading library datasets:
</p><ul style="padding-left: 1em; list-style-type: disc;">
+ %if 'gz' in comptypes:
+ <li>gzip: Compression is fastest and yields a larger file, making it more suitable for fast network connections.
+ %if trans.app.config.upstream_gzip:
+ NOTE: The file you receive will be an uncompressed .tar file - this is because the Galaxy server compresses it and your browser decompresses it on the fly.
+ %endif
+ </li>
+ %endif
%if 'bz2' in comptypes:
<li>bzip2: Compression takes the most time but is better for slower network connections (that transfer slower than the rate of compression) since the resulting file size is smallest.</li>
%endif
- %if 'gz' in comptypes:
- <li>gzip: Compression is faster and yields a larger file, making it more suitable for fast network connections.</li>
- %endif
%if 'zip' in comptypes:
<li>ZIP: Not recommended but is provided as an option for those on Windows without WinZip (since WinZip can read .bz2 and .gz files).</li>
%endif
1
0
galaxy-dist commit 9114bd088776: Better handling of return key in search+select.
by commits-noreply@bitbucket.org 07 Jun '10
by commits-noreply@bitbucket.org 07 Jun '10
07 Jun '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User jeremy goecks <jeremy.goecks(a)emory.edu>
# Date 1275753610 14400
# Node ID 9114bd0887769b9ffe570b71f90ab95be68baa44
# Parent 21ddc9f843be29515ea6f260a73a710288606104
Better handling of return key in search+select.
--- a/static/scripts/galaxy.base.js
+++ b/static/scripts/galaxy.base.js
@@ -287,9 +287,16 @@ function replace_big_select_inputs(min_l
// case a user may have manually entered a value that needs to be refreshed).
text_input_elt.bind("result", try_refresh_fn);
text_input_elt.keyup( function(e) {
- try_refresh_fn();
+ if ( e.keyCode === 13 ) // Return key
+ try_refresh_fn();
});
-
+
+ // Disable return key so that it does not submit the form automatically. This is done because elememnt should behave like a
+ // select (enter = select), not text input (enter = submit form).
+ text_input_elt.keydown( function(e) {
+ if ( e.keyCode === 13 ) // Return key
+ return false;
+ });
}
});
}
--- a/static/scripts/packed/galaxy.base.js
+++ b/static/scripts/packed/galaxy.base.js
@@ -1,1 +1,1 @@
-$(document).ready(function(){replace_big_select_inputs()});$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function ensure_popup_helper(){if($("#popup-helper").length===0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}function make_popupmenu
(c,b){ensure_popup_helper();var a=$("<ul id='"+c.attr("id")+"-menu'></ul>");$.each(b,function(f,e){if(e){$("<li/>").html(f).click(e).appendTo(a)}else{$("<li class='head'/>").html(f).appendTo(a)}});var d=$("<div class='popmenu-wrapper'>");d.append(a).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(c,d)}function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}else{if(e=="_top"){g=window.top}}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.addClass("popup").show()})}function array_length(b){if(b.length){return b.length}var c=0;for(var a in b){c++}return c}function naturalSort(i,g){var n=/(-?[0-9\.]+)/g,j=i.toString().toLowerCase()||"",f=g.toString().t
oLowerCase()||"",k=String.fromCharCode(0),l=j.replace(n,k+"$1"+k).split(k),e=f.replace(n,k+"$1"+k).split(k),d=(new Date(j)).getTime(),m=d?(new Date(f)).getTime():null;if(m){if(d<m){return -1}else{if(d>m){return 1}}}for(var h=0,c=Math.max(l.length,e.length);h<c;h++){oFxNcL=parseFloat(l[h])||l[h];oFyNcL=parseFloat(e[h])||e[h];if(oFxNcL<oFyNcL){return -1}else{if(oFxNcL>oFyNcL){return 1}}}return 0}function replace_big_select_inputs(a){if(typeof jQuery().autocomplete=="undefined"){return}if(a===undefined){a=20}$("select").each(function(){var d=$(this);if(d.find("option").length<a){return}if(d.attr("multiple")==true){return}var j=d.attr("value");var b=$("<input type='text' class='text-and-autocomplete-select'></input>");b.attr("size",40);b.attr("name",d.attr("name"));b.attr("id",d.attr("id"));b.click(function(){var k=$(this).attr("value");$(this).attr("value","Loading...");$(this).showAllInCache();$(this).attr("value",k);$(this).select()});var e=[];var g={};d.children("option").ea
ch(function(){var l=$(this).text();var k=$(this).attr("value");e.push(l);g[l]=k;g[k]=k;if(k==j){b.attr("value",l)}});if(j==""||j=="?"){b.attr("value","Click to Search or Select")}if(d.attr("name")=="dbkey"){e=e.sort(naturalSort)}var f={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:1000,minChars:0,hideForLessThanMinChars:false};b.autocomplete(e,f);d.replaceWith(b);var i=function(){var l=b.attr("value");var k=g[l];if(k!==null&&k!==undefined){b.attr("value",k)}else{if(j!=""){b.attr("value",j)}else{b.attr("value","?")}}};b.parents("form").submit(function(){i()});$(document).bind("convert_dbkeys",function(){i()});if(d.attr("refresh_on_change")=="true"){var c=d.attr("refresh_on_change_values");if(c!==undefined){c=c.split(",")}var h=function(){var m=b.attr("value");var l=g[m];if(l!==null&&l!==undefined){refresh=false;if(c!==undefined){for(var k=0;k<c.length;k++){if(l==c[k]){refresh=true;break}}}else{refresh=true}if(refresh){b.attr("value",l);b.parents("for
m").submit()}}};b.bind("result",h);b.keyup(function(k){h()})}})}function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).live("click",function(){if($("#renaming-active").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text(k)}else{j=$("<input type='text'></input>").attr({value:k,size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){l.text(o);if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(d,a,c){var b=function(){try{var e=$.jStore.store("history_expand_state");if(e){for(var g in e){$("#"+g+" div.historyItemBody").show()}}}catch(f){$.jSto
re.remove("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}d.each(function(){var j=this.id;var h=$(this).children("div.historyItemBody");var i=h.find("pre.peek");$(this).find(".historyItemTitleBar > .historyItemTitle").wrap("<a href='javascript:void(0);'></a>").click(function(){if(h.is(":visible")){if($.browser.mozilla){i.css("overflow","hidden")}h.slideUp("fast");if(!c){var k=$.jStore.store("history_expand_state");if(k){delete k[j];$.jStore.store("history_expand_state",k)}}}else{h.slideDown("fast",function(){if($.browser.mozilla){i.css("overflow","auto")}});if(!c){var k=$.jStore.store("history_expand_state");if(k===undefined){k={}}k[j]=true;$.jStore.store("history_expand_state",k)}}return false})});$("#top-links > a.toggle").click(function(){var h=$.jStore.store("history_expand_state");if(h===undefined){h={}}$("div.historyItemBody:visible").each(function(){
if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(h){delete h[$(this).parent().attr("id")]}});$.jStore.store("history_expand_state",h)}).show()};if(a){b()}else{$.jStore.init("galaxy");$.jStore.engineReady(function(){b()})}}function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}$(document).ready(function(){$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tipsy){$(".tooltip").tipsy({gravity:"s"})}make_popup_menus()});
+$(document).ready(function(){replace_big_select_inputs()});$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function ensure_popup_helper(){if($("#popup-helper").length===0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}function make_popupmenu
(c,b){ensure_popup_helper();var a=$("<ul id='"+c.attr("id")+"-menu'></ul>");$.each(b,function(f,e){if(e){$("<li/>").html(f).click(e).appendTo(a)}else{$("<li class='head'/>").html(f).appendTo(a)}});var d=$("<div class='popmenu-wrapper'>");d.append(a).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(c,d)}function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}else{if(e=="_top"){g=window.top}}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.addClass("popup").show()})}function array_length(b){if(b.length){return b.length}var c=0;for(var a in b){c++}return c}function naturalSort(i,g){var n=/(-?[0-9\.]+)/g,j=i.toString().toLowerCase()||"",f=g.toString().t
oLowerCase()||"",k=String.fromCharCode(0),l=j.replace(n,k+"$1"+k).split(k),e=f.replace(n,k+"$1"+k).split(k),d=(new Date(j)).getTime(),m=d?(new Date(f)).getTime():null;if(m){if(d<m){return -1}else{if(d>m){return 1}}}for(var h=0,c=Math.max(l.length,e.length);h<c;h++){oFxNcL=parseFloat(l[h])||l[h];oFyNcL=parseFloat(e[h])||e[h];if(oFxNcL<oFyNcL){return -1}else{if(oFxNcL>oFyNcL){return 1}}}return 0}function replace_big_select_inputs(a){if(typeof jQuery().autocomplete=="undefined"){return}if(a===undefined){a=20}$("select").each(function(){var d=$(this);if(d.find("option").length<a){return}if(d.attr("multiple")==true){return}var j=d.attr("value");var b=$("<input type='text' class='text-and-autocomplete-select'></input>");b.attr("size",40);b.attr("name",d.attr("name"));b.attr("id",d.attr("id"));b.click(function(){var k=$(this).attr("value");$(this).attr("value","Loading...");$(this).showAllInCache();$(this).attr("value",k);$(this).select()});var e=[];var g={};d.children("option").ea
ch(function(){var l=$(this).text();var k=$(this).attr("value");e.push(l);g[l]=k;g[k]=k;if(k==j){b.attr("value",l)}});if(j==""||j=="?"){b.attr("value","Click to Search or Select")}if(d.attr("name")=="dbkey"){e=e.sort(naturalSort)}var f={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:1000,minChars:0,hideForLessThanMinChars:false};b.autocomplete(e,f);d.replaceWith(b);var i=function(){var l=b.attr("value");var k=g[l];if(k!==null&&k!==undefined){b.attr("value",k)}else{if(j!=""){b.attr("value",j)}else{b.attr("value","?")}}};b.parents("form").submit(function(){i()});$(document).bind("convert_dbkeys",function(){i()});if(d.attr("refresh_on_change")=="true"){var c=d.attr("refresh_on_change_values");if(c!==undefined){c=c.split(",")}var h=function(){var m=b.attr("value");var l=g[m];if(l!==null&&l!==undefined){refresh=false;if(c!==undefined){for(var k=0;k<c.length;k++){if(l==c[k]){refresh=true;break}}}else{refresh=true}if(refresh){b.attr("value",l);b.parents("for
m").submit()}}};b.bind("result",h);b.keyup(function(k){if(k.keyCode===13){h()}});b.keydown(function(k){if(k.keyCode===13){return false}})}})}function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).live("click",function(){if($("#renaming-active").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text(k)}else{j=$("<input type='text'></input>").attr({value:k,size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){l.text(o);if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(d,a,c){var b=function(){try{var e=$.jStore.store("history_expand_state");i
f(e){for(var g in e){$("#"+g+" div.historyItemBody").show()}}}catch(f){$.jStore.remove("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}d.each(function(){var j=this.id;var h=$(this).children("div.historyItemBody");var i=h.find("pre.peek");$(this).find(".historyItemTitleBar > .historyItemTitle").wrap("<a href='javascript:void(0);'></a>").click(function(){if(h.is(":visible")){if($.browser.mozilla){i.css("overflow","hidden")}h.slideUp("fast");if(!c){var k=$.jStore.store("history_expand_state");if(k){delete k[j];$.jStore.store("history_expand_state",k)}}}else{h.slideDown("fast",function(){if($.browser.mozilla){i.css("overflow","auto")}});if(!c){var k=$.jStore.store("history_expand_state");if(k===undefined){k={}}k[j]=true;$.jStore.store("history_expand_state",k)}}return false})});$("#top-links > a.toggle").click(function(){var h=$.jStore.store("history_expand_sta
te");if(h===undefined){h={}}$("div.historyItemBody:visible").each(function(){if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(h){delete h[$(this).parent().attr("id")]}});$.jStore.store("history_expand_state",h)}).show()};if(a){b()}else{$.jStore.init("galaxy");$.jStore.engineReady(function(){b()})}}function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}$(document).ready(function(){$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tipsy){$(".tooltip").tipsy({gravity:"s"})}make_popup_menus()});
1
0
galaxy-dist commit 21ddc9f843be: Prevent workflow forms from being submitted twice when dynamic options are refreshed, resulting in AJAX error and inability to savewq
by commits-noreply@bitbucket.org 07 Jun '10
by commits-noreply@bitbucket.org 07 Jun '10
07 Jun '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kanwei Li <kanwei(a)gmail.com>
# Date 1275690470 14400
# Node ID 21ddc9f843be29515ea6f260a73a710288606104
# Parent 56e2793886dc2d1547bb86f32a13d0e365f8fecd
Prevent workflow forms from being submitted twice when dynamic options are refreshed, resulting in AJAX error and inability to savewq
--- a/templates/workflow/editor.mako
+++ b/templates/workflow/editor.mako
@@ -328,6 +328,7 @@
type: 'POST',
dataType: 'json',
success: function( data ) {
+ workflow.active_form_has_changes = false;
node.update_field_data( data );
},
beforeSubmit: function( data ) {
1
0
galaxy-dist commit 5610a35bf9a6: Add the CBI Rice Mart data source tool to the distribution.
by commits-noreply@bitbucket.org 07 Jun '10
by commits-noreply@bitbucket.org 07 Jun '10
07 Jun '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1275680998 14400
# Node ID 5610a35bf9a67b0e43f02a433163232ab3f7a998
# Parent 84880085415b7b53ead611ccffee39b0ab9e0d4b
Add the CBI Rice Mart data source tool to the distribution.
--- /dev/null
+++ b/tools/data_source/cbi_rice_mart.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!--
+ If the value of 'URL_method' is 'get', the request will consist of the value of 'URL' coming back in
+ the initial response. If value of 'URL_method' is 'post', any additional params coming back in the
+ initial response ( in addition to 'URL' ) will be encoded and appended to URL and a post will be performed.
+-->
+<tool name="CBI Rice Mart" id="cbi_rice_mart" tool_type="data_source" version="1.0.1">
+ <description>rice mart</description>
+ <command interpreter="python">data_source.py $output $__app__.config.output_size_limit</command>
+ <inputs action="http://ricemart.cbi.edu.cn/biomart/martview/" check_values="false" method="get" target="_top">
+ <display>go to RMap rice mart $GALAXY_URL</display>
+ <param name="GALAXY_URL" type="baseurl" value="/tool_runner/biomart" />
+ </inputs>
+ <request_param_translation>
+ <request_param galaxy_name="URL" remote_name="URL" missing="">
+ <append_param separator="&" first_separator="?" join="=">
+ <value name="_export" missing="1" />
+ <value name="GALAXY_URL" missing="0" />
+ </append_param>
+ </request_param>
+ <request_param galaxy_name="data_type" remote_name="exportView_outputformat" missing="tabular" >
+ <value_translation>
+ <value galaxy_value="tabular" remote_value="TSV" />
+ </value_translation>
+ </request_param>
+ <request_param galaxy_name="URL_method" remote_name="URL_method" missing="get" />
+ <request_param galaxy_name="dbkey" remote_name="dbkey" missing="?" />
+ <request_param galaxy_name="organism" remote_name="organism" missing="" />
+ <request_param galaxy_name="table" remote_name="table" missing="" />
+ <request_param galaxy_name="description" remote_name="description" missing="" />
+ <request_param galaxy_name="name" remote_name="name" missing="Rice mart query" />
+ <request_param galaxy_name="info" remote_name="info" missing="" />
+ </request_param_translation>
+ <uihints minwidth="800"/>
+ <outputs>
+ <data name="output" format="tabular" />
+ </outputs>
+ <options sanitize="False" refresh="True"/>
+</tool>
--- a/tool_conf.xml.sample
+++ b/tool_conf.xml.sample
@@ -9,6 +9,7 @@
<tool file="data_source/microbial_import.xml" /><tool file="data_source/biomart.xml" /><tool file="data_source/biomart_test.xml" />
+ <tool file="data_source/cbi_rice_mart.xml" /><tool file="data_source/gramene_mart.xml" /><tool file="data_source/fly_modencode.xml" /><tool file="data_source/flymine.xml" />
1
0
galaxy-dist commit 56e2793886dc: Fix for library dataset information page, link to history items using hda.history_id rather than hda.history.id.
by commits-noreply@bitbucket.org 07 Jun '10
by commits-noreply@bitbucket.org 07 Jun '10
07 Jun '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1275688990 14400
# Node ID 56e2793886dc2d1547bb86f32a13d0e365f8fecd
# Parent 5610a35bf9a67b0e43f02a433163232ab3f7a998
Fix for library dataset information page, link to history items using hda.history_id rather than hda.history.id.
--- a/templates/library/common/ldda_info.mako
+++ b/templates/library/common/ldda_info.mako
@@ -148,7 +148,7 @@
</thead>
%for hda in associated_hdas:
<tr>
- <td><a target="_blank" href="${h.url_for( controller='history', action='view', id=trans.security.encode_id( hda.history.id ) )}">${hda.history.get_display_name()}</a></td>
+ <td><a target="_blank" href="${h.url_for( controller='history', action='view', id=trans.security.encode_id( hda.history_id ) )}">${hda.history.get_display_name()}</a></td><td>${hda.get_display_name()}</td><td>${time_ago( hda.update_time )}</td><td>
1
0
galaxy-dist commit 84880085415b: Add the ratmine datasource tool to main's tool config.
by commits-noreply@bitbucket.org 07 Jun '10
by commits-noreply@bitbucket.org 07 Jun '10
07 Jun '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1275677102 14400
# Node ID 84880085415b7b53ead611ccffee39b0ab9e0d4b
# Parent 6dde140d0cfd53820f9cbb83bbb44338ac8bd6aa
Add the ratmine datasource tool to main's tool config.
--- a/tool_conf.xml.main
+++ b/tool_conf.xml.main
@@ -10,6 +10,7 @@
<tool file="data_source/gramene_mart.xml" /><tool file="data_source/flymine.xml" /><tool file="data_source/fly_modencode.xml" />
+ <tool file="data_source/ratmine.xml" /><tool file="data_source/worm_modencode.xml" /><tool file="data_source/wormbase.xml" /><tool file="data_source/eupathdb.xml" />
1
0
galaxy-dist commit dd69c382eff1: lims: added new feature where the datasets are be automatically renamed using a setting with the request_type. This makes solves the same dataset name problem on SOLiD
by commits-noreply@bitbucket.org 07 Jun '10
by commits-noreply@bitbucket.org 07 Jun '10
07 Jun '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User rc
# Date 1275671936 14400
# Node ID dd69c382eff1d3c0c160bc3ec392b06671317fd0
# Parent d01207f24908bc3f6d5323689f0aa46557f4d254
lims: added new feature where the datasets are be automatically renamed using a setting with the request_type. This makes solves the same dataset name problem on SOLiD
--- a/templates/admin/requests/create_request_type.mako
+++ b/templates/admin/requests/create_request_type.mako
@@ -70,6 +70,15 @@
<input type="text" name="data_dir" value="" size="40"/></div><div class="form-row">
+ <label>Add experiment name and the sample name to the dataset name?</label>
+ ${rename_dataset_selectbox.get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ The datasets are renamed by prepending the experiment name and the sample name to the dataset name. <br/>This
+ makes sure that dataset names remain unique in Galaxy even when they have the
+ same name in the sequencer.
+ </div>
+ </div>
+ <div class="form-row"><div style="float: left; width: 250px; margin-right: 10px;"><input type="hidden" name="new" value="submitted" size="40"/></div>
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -1476,6 +1476,9 @@ class RequestEvent( object ):
self.comment = comment
class RequestType( object ):
+ rename_dataset_options = Bunch( NO = 'Do not rename',
+ SAMPLE_NAME = 'Preprend sample name',
+ EXPERIMENT_AND_SAMPLE_NAME = 'Prepend experiment and sample name')
permitted_actions = get_permitted_actions( filter='REQUEST_TYPE' )
def __init__(self, name=None, desc=None, request_form=None, sample_form=None,
datatx_info=None):
--- a/templates/admin/requests/view_request_type.mako
+++ b/templates/admin/requests/view_request_type.mako
@@ -62,6 +62,15 @@
<input type="text" name="data_dir" value="${request_type.datatx_info.get('data_dir', '')}" size="40"/></div><div class="form-row">
+ <label>Add experiment name and the sample name to the dataset name?</label>
+ ${rename_dataset_selectbox.get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ The datasets are renamed by prepending the experiment name and the sample name to the dataset name. <br/>This
+ makes sure that dataset names remain unique in Galaxy even when they have the
+ same name in the sequencer.
+ </div>
+ </div>
+ <div class="form-row"><input type="submit" name="save_changes" value="Save changes"/></div></form>
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -221,7 +221,6 @@ class RequestsAdmin( BaseController ):
@web.json
def get_file_details( self, trans, id=None, file=None, folder_path=None ):
- print >> sys.stderr, 'get_file_details', id, file
def print_ticks(d):
pass
# Avoid caching
@@ -1623,7 +1622,7 @@ class RequestsAdmin( BaseController ):
else:
sample.dataset_files.append(dict(filepath=filepath,
status=sample.transfer_status.NOT_STARTED,
- name=filepath.split('/')[-1],
+ name=self.__dataset_name(sample, filepath.split('/')[-1]),
error_msg='',
size=sample.dataset_size(filepath)))
trans.sa_session.add( sample )
@@ -1638,7 +1637,16 @@ class RequestsAdmin( BaseController ):
action='show_datatx_page',
sample_id=trans.security.encode_id(sample.id),
folder_path=folder_path))
-
+
+ def __dataset_name(self, sample, filepath):
+ name = filepath.split('/')[-1]
+ opt = sample.request.type.datatx_info.get('rename_dataset', sample.request.type.rename_dataset_options.NO)
+ if opt == sample.request.type.rename_dataset_options.NO:
+ return name
+ elif opt == sample.request.type.rename_dataset_options.SAMPLE_NAME:
+ return sample.name+'_'+name
+ elif opt == sample.request.type.rename_dataset_options.EXPERIMENT_AND_SAMPLE_NAME:
+ return sample.request.name+'_'+sample.name+'_'+name
def __setup_datatx_user(self, trans, library, folder):
'''
This method sets up the datatx user:
@@ -1830,7 +1838,8 @@ class RequestsAdmin( BaseController ):
return trans.fill_template( '/admin/requests/view_request_type.mako',
request_type=rt,
forms=get_all_forms( trans ),
- states_list=rt.states )
+ states_list=rt.states,
+ rename_dataset_selectbox=self.__rename_dataset_selectbox(trans, rt) )
def __view_form(self, trans, **kwd):
try:
fd = trans.sa_session.query( trans.app.model.FormDefinition ).get( trans.security.decode_id(kwd['id']) )
@@ -1855,7 +1864,8 @@ class RequestsAdmin( BaseController ):
rt_info_widgets=rt_info,
rt_states_widgets=rt_states,
message=message,
- status=status)
+ status=status,
+ rename_dataset_selectbox=self.__rename_dataset_selectbox(trans))
elif params.get( 'remove_state_button', False ):
rt_info, rt_states = self.__create_request_type_form(trans, **kwd)
index = int(params.get( 'remove_state_button', '' ).split(" ")[2])
@@ -1864,7 +1874,8 @@ class RequestsAdmin( BaseController ):
rt_info_widgets=rt_info,
rt_states_widgets=rt_states,
message=message,
- status=status)
+ status=status,
+ rename_dataset_selectbox=self.__rename_dataset_selectbox(trans))
elif params.get( 'save_request_type', False ):
rt, message = self.__save_request_type(trans, **kwd)
if not rt:
@@ -1888,7 +1899,8 @@ class RequestsAdmin( BaseController ):
rt.datatx_info = dict(host=util.restore_text( params.get( 'host', '' ) ),
username=util.restore_text( params.get( 'username', '' ) ),
password=params.get( 'password', '' ),
- data_dir=util.restore_text( params.get( 'data_dir', '' ) ))
+ data_dir=util.restore_text( params.get( 'data_dir', '' ) ),
+ rename_dataset=util.restore_text( params.get('rename_dataset', False) ))
trans.sa_session.add( rt )
trans.sa_session.flush()
return trans.response.send_redirect( web.url_for( controller='requests_admin',
@@ -1903,7 +1915,8 @@ class RequestsAdmin( BaseController ):
rt_info_widgets=rt_info,
rt_states_widgets=rt_states,
message=message,
- status=status)
+ status=status,
+ rename_dataset_selectbox=self.__rename_dataset_selectbox(trans))
def __create_request_type_form(self, trans, **kwd):
request_forms=get_all_forms( trans,
filter=dict(deleted=False),
@@ -1949,6 +1962,19 @@ class RequestsAdmin( BaseController ):
break
return rt_info, rt_states
+ def __rename_dataset_selectbox(self, trans, rt=None):
+ if rt:
+ sel_opt = rt.datatx_info.get('rename_dataset', trans.app.model.RequestType.rename_dataset_options.NO)
+ else:
+ sel_opt = trans.app.model.RequestType.rename_dataset_options.NO
+ rename_dataset_selectbox = SelectField('rename_dataset')
+ for opt, opt_name in trans.app.model.RequestType.rename_dataset_options.items():
+ if sel_opt == opt_name:
+ rename_dataset_selectbox.add_option(opt_name, opt_name, selected=True)
+ else:
+ rename_dataset_selectbox.add_option(opt_name, opt_name)
+ return rename_dataset_selectbox
+
def __save_request_type(self, trans, **kwd):
params = util.Params( kwd )
rt = trans.app.model.RequestType()
@@ -1960,7 +1986,8 @@ class RequestsAdmin( BaseController ):
rt.datatx_info = dict(host=util.restore_text( params.get( 'host', '' ) ),
username=util.restore_text( params.get( 'username', '' ) ),
password=params.get( 'password', '' ),
- data_dir=util.restore_text( params.get( 'data_dir', '' ) ))
+ data_dir=util.restore_text( params.get( 'data_dir', '' ) ),
+ rename_dataset=util.restore_text( params.get('rename_dataset', '') ))
trans.sa_session.add( rt )
trans.sa_session.flush()
# set sample states
--- a/templates/admin/requests/get_data.mako
+++ b/templates/admin/requests/get_data.mako
@@ -55,6 +55,8 @@
<h2>Data transfer from Sequencer</h2><h3>Sample "${sample.name}" of Request "${sample.request.name}"</h3>
+<br/>
+<br/><ul class="manage-table-actions">
%if sample.request.submitted() and sample.inprogress_dataset_files():
@@ -131,7 +133,7 @@
<input type="submit" name="open_folder" value="Open folder"/><input type="submit" name="folder_up" value="Up"/></div>
- <div class="form-row">
+ <div class="form-row"><select name="files_list" id="files_list" style="max-width: 98%; width: 98%; height: 150px; font-size: 100%;" onChange="display_file_details(${sample.id}, '${folder_path}')" multiple>
%for index, f in enumerate(files):
<option value="${f}">${f}</option>
1
0
galaxy-dist commit a76d05bb41e1: Fixes and enhancements to the reports webapp:
by commits-noreply@bitbucket.org 07 Jun '10
by commits-noreply@bitbucket.org 07 Jun '10
07 Jun '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1275672554 14400
# Node ID a76d05bb41e1c1f1eeaa93a18289eeed1213199b
# Parent dd69c382eff1d3c0c160bc3ec392b06671317fd0
Fixes and enhancements to the reports webapp:
0) The report that is initially displayed is now the number of jobs per day for the current month rather than the grid displaying all jobs for today.
1) Eliminate eagerloading when querying jobs so that queries are much faster
2) Fix the disk space ( system ) report, and add a new feature that displays all active ( undeleted ) hda and ldda pointers to a specific dataset.
3) Standardize request parameters so that queries can more easily be built using parameters from the request.
4) A few other miscellaneous bug fixes in the reports.
--- a/templates/webapps/reports/registered_users.mako
+++ b/templates/webapps/reports/registered_users.mako
@@ -2,7 +2,7 @@
<%namespace file="/message.mako" import="render_msg" />
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
--- a/templates/webapps/reports/jobs_user_per_month.mako
+++ b/templates/webapps/reports/jobs_user_per_month.mako
@@ -4,7 +4,7 @@
<% from galaxy import util %>
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
@@ -27,7 +27,7 @@
<tr class="tr">
%endif
<td>${job[2]} ${job[3]}</td>
- <td><a href="${h.url_for( controller='jobs', action='user_for_month', email=email, month=job[0] )}">${job[1]}</a></td>
+ <td><a href="${h.url_for( controller='jobs', action='user_for_month', email=email, specified_date=job[0]+'-01' )}">${job[1]}</a></td></tr><% ctr += 1 %>
%endfor
--- a/lib/galaxy/webapps/reports/controllers/jobs.py
+++ b/lib/galaxy/webapps/reports/controllers/jobs.py
@@ -63,7 +63,7 @@ class SpecifiedDateListGrid( grids.Grid
model_class=model.User,
link=( lambda item: dict( operation="user_per_month", id=item.id, webapp="reports" ) ),
attach_popup=False ),
- grids.StateColumn( "All", key="state", model_class=model.Job, visible=False, filterable="advanced" )
+ grids.StateColumn( "state", key="state", model_class=model.Job, visible=False, filterable="advanced" )
]
columns.append( grids.MulticolFilterColumn( "Search",
cols_to_filter=[ columns[1], columns[2] ],
@@ -78,45 +78,59 @@ class SpecifiedDateListGrid( grids.Grid
def build_initial_query( self, trans, **kwd ):
specified_date = kwd.get( 'specified_date', 'All' )
if specified_date == 'All':
- return trans.sa_session.query( self.model_class )
+ return trans.sa_session.query( self.model_class ) \
+ .enable_eagerloads( False )
year, month, day = map( int, specified_date.split( "-" ) )
start_date = date( year, month, day )
end_date = start_date + timedelta( days=1 )
- return trans.sa_session.query( self.model_class ).filter( and_( self.model_class.table.c.create_time >= start_date,
- self.model_class.table.c.create_time < end_date ) )
+ return trans.sa_session.query( self.model_class ) \
+ .filter( and_( self.model_class.table.c.create_time >= start_date,
+ self.model_class.table.c.create_time < end_date ) ) \
+ .enable_eagerloads( False )
class SpecifiedDateInErrorListGrid( SpecifiedDateListGrid ):
def build_initial_query( self, trans, **kwd ):
specified_date = kwd.get( 'specified_date', 'All' )
if specified_date == 'All':
- return trans.sa_session.query( self.model_class ).filter( self.model_class.table.c.state == model.Job.states.ERROR )
+ return trans.sa_session.query( self.model_class ) \
+ .filter( self.model_class.table.c.state == model.Job.states.ERROR ) \
+ .enable_eagerloads( False )
year, month, day = map( int, specified_date.split( "-" ) )
start_date = date( year, month, day )
end_date = start_date + timedelta( days=1 )
- return trans.sa_session.query( self.model_class ).filter( and_( self.model_class.table.c.state == model.Job.states.ERROR,
- self.model_class.table.c.create_time >= start_date,
- self.model_class.table.c.create_time < end_date ) )
+ return trans.sa_session.query( self.model_class ) \
+ .filter( and_( self.model_class.table.c.state == model.Job.states.ERROR,
+ self.model_class.table.c.create_time >= start_date,
+ self.model_class.table.c.create_time < end_date ) ) \
+ .enable_eagerloads( False )
class AllUnfinishedListGrid( SpecifiedDateListGrid ):
def build_initial_query( self, trans, **kwd ):
specified_date = kwd.get( 'specified_date', 'All' )
if specified_date == 'All':
- return trans.sa_session.query( self.model_class ).filter( not_( or_( model.Job.table.c.state == model.Job.states.OK,
- model.Job.table.c.state == model.Job.states.ERROR,
- model.Job.table.c.state == model.Job.states.DELETED ) ) )
+ return trans.sa_session.query( self.model_class ) \
+ .filter( not_( or_( model.Job.table.c.state == model.Job.states.OK,
+ model.Job.table.c.state == model.Job.states.ERROR,
+ model.Job.table.c.state == model.Job.states.DELETED ) ) ) \
+ .enable_eagerloads( False )
year, month, day = map( int, specified_date.split( "-" ) )
start_date = date( year, month, day )
end_date = start_date + timedelta( days=1 )
- return trans.sa_session.query( self.model_class ).filter( and_( not_( or_( model.Job.table.c.state == model.Job.states.OK,
- model.Job.table.c.state == model.Job.states.ERROR,
- model.Job.table.c.state == model.Job.states.DELETED ) ),
- self.model_class.table.c.create_time >= start_date,
- self.model_class.table.c.create_time < end_date ) )
+ return trans.sa_session.query( self.model_class ) \
+ .filter( and_( not_( or_( model.Job.table.c.state == model.Job.states.OK,
+ model.Job.table.c.state == model.Job.states.ERROR,
+ model.Job.table.c.state == model.Job.states.DELETED ) ),
+ self.model_class.table.c.create_time >= start_date,
+ self.model_class.table.c.create_time < end_date ) ) \
+ .enable_eagerloads( False )
class UserForMonthListGrid( SpecifiedDateListGrid ):
def build_initial_query( self, trans, **kwd ):
email = util.restore_text( kwd.get( 'email', '' ) )
- year, month = map( int, kwd.get( 'month', datetime.utcnow().strftime( "%Y-%m" ) ).split( "-" ) )
+ # If specified_date is not received, we'll default to the current month
+ specified_date = kwd.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
+ specified_month = specified_date[ :7 ]
+ year, month = map( int, specified_month.split( "-" ) )
start_date = date( year, month, 1 )
end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
return trans.sa_session.query( model.Job ) \
@@ -127,19 +141,22 @@ class UserForMonthListGrid( SpecifiedDat
model.User.table.c.email == email,
model.Job.table.c.create_time >= start_date,
model.Job.table.c.create_time < end_date ) ) \
- .order_by( desc( model.Job.table.c.create_time ) )
+ .enable_eagerloads( False )
class ToolForMonthListGrid( SpecifiedDateListGrid ):
def build_initial_query( self, trans, **kwd ):
+ # If specified_date is not received, we'll default to the current month
+ specified_date = kwd.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
+ specified_month = specified_date[ :7 ]
tool_id = util.restore_text( kwd.get( 'tool_id', '' ) )
- year, month = map( int, kwd.get( 'month', datetime.utcnow().strftime( "%Y-%m" ) ).split( "-" ) )
+ year, month = map( int, specified_month.split( "-" ) )
start_date = date( year, month, 1 )
end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
- return trans.sa_session.query( model.Job ) \
- .filter( and_( model.Job.table.c.tool_id == tool_id,
- model.Job.table.c.create_time >= start_date,
- model.Job.table.c.create_time < end_date ) ) \
- .order_by( desc( model.Job.table.c.create_time ) )
+ return trans.sa_session.query( self.model_class ) \
+ .filter( and_( self.model_class.table.c.tool_id == tool_id,
+ self.model_class.table.c.create_time >= start_date,
+ self.model_class.table.c.create_time < end_date ) ) \
+ .enable_eagerloads( False )
class Jobs( BaseController ):
@@ -158,8 +175,7 @@ class Jobs( BaseController ):
action='job_info',
**kwd ) )
if operation == "tool_per_month":
- # The received id is the job id, so we need to get the id of the user
- # that submitted the job.
+ # The received id is the job id, so we need to get the jobs tool_id.
job_id = kwd.get( 'id', None )
job = get_job( trans, job_id )
kwd[ 'tool_id' ] = job.tool_id
@@ -194,8 +210,7 @@ class Jobs( BaseController ):
action='job_info',
**kwd ) )
if operation == "tool_per_month":
- # The received id is the job id, so we need to get the id of the user
- # that submitted the job.
+ # The received id is the job id, so we need to get the jobs tool_id.
job_id = kwd.get( 'id', None )
job = get_job( trans, job_id )
kwd[ 'tool_id' ] = job.tool_id
@@ -222,7 +237,10 @@ class Jobs( BaseController ):
params = util.Params( kwd )
message = ''
monitor_email = params.get( 'monitor_email', 'monitor(a)bx.psu.edu' )
- year, month = map( int, params.get( 'month', datetime.utcnow().strftime( "%Y-%m" ) ).split( "-" ) )
+ # If specified_date is not received, we'll default to the current month
+ specified_date = kwd.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
+ specified_month = specified_date[ :7 ]
+ year, month = map( int, specified_month.split( "-" ) )
start_date = date( year, month, 1 )
end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
month_label = start_date.strftime( "%B" )
@@ -254,7 +272,10 @@ class Jobs( BaseController ):
def specified_month_in_error( self, trans, **kwd ):
params = util.Params( kwd )
message = ''
- year, month = map( int, params.get( 'month', datetime.utcnow().strftime( "%Y-%m" ) ).split( "-" ) )
+ # If specified_date is not received, we'll default to the current month
+ specified_date = kwd.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
+ specified_month = specified_date[ :7 ]
+ year, month = map( int, specified_month.split( "-" ) )
start_date = date( year, month, 1 )
end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
month_label = start_date.strftime( "%B" )
@@ -289,8 +310,7 @@ class Jobs( BaseController ):
action='job_info',
**kwd ) )
if operation == "tool_per_month":
- # The received id is the job id, so we need to get the id of the user
- # that submitted the job.
+ # The received id is the job id, so we need to get the jobs tool_id.
job_id = kwd.get( 'id', None )
job = get_job( trans, job_id )
kwd[ 'tool_id' ] = job.tool_id
@@ -332,7 +352,9 @@ class Jobs( BaseController ):
row.total_jobs,
row.date.strftime( "%B" ),
row.date.strftime( "%Y" ) ) )
- return trans.fill_template( '/webapps/reports/jobs_per_month_all.mako', jobs=jobs, message=message )
+ return trans.fill_template( '/webapps/reports/jobs_per_month_all.mako',
+ jobs=jobs,
+ message=message )
@web.expose
def per_month_in_error( self, trans, **kwd ):
params = util.Params( kwd )
@@ -349,7 +371,9 @@ class Jobs( BaseController ):
row.total_jobs,
row.date.strftime( "%B" ),
row.date.strftime( "%Y" ) ) )
- return trans.fill_template( '/webapps/reports/jobs_per_month_in_error.mako', jobs=jobs, message=message )
+ return trans.fill_template( '/webapps/reports/jobs_per_month_in_error.mako',
+ jobs=jobs,
+ message=message )
@web.expose
def per_user( self, trans, **kwd ):
params = util.Params( kwd )
@@ -398,8 +422,7 @@ class Jobs( BaseController ):
action='job_info',
**kwd ) )
if operation == "tool_per_month":
- # The received id is the job id, so we need to get the id of the user
- # that submitted the job.
+ # The received id is the job id, so we need to get the jobs tool_id.
job_id = kwd.get( 'id', None )
job = get_job( trans, job_id )
kwd[ 'tool_id' ] = job.tool_id
@@ -434,12 +457,15 @@ class Jobs( BaseController ):
for row in q.execute():
jobs.append( ( row.tool_id,
row.total_jobs ) )
- return trans.fill_template( '/webapps/reports/jobs_per_tool.mako', jobs=jobs, message=message )
+ return trans.fill_template( '/webapps/reports/jobs_per_tool.mako',
+ jobs=jobs,
+ message=message )
@web.expose
def tool_per_month( self, trans, **kwd ):
params = util.Params( kwd )
message = ''
tool_id = params.get( 'tool_id', 'Add a column1' )
+ specified_date = params.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
q = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ).label( 'date' ),
sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
whereclause = model.Job.table.c.tool_id == tool_id,
@@ -452,7 +478,11 @@ class Jobs( BaseController ):
row.total_jobs,
row.date.strftime( "%B" ),
row.date.strftime( "%Y" ) ) )
- return trans.fill_template( '/webapps/reports/jobs_tool_per_month.mako', tool_id=tool_id, jobs=jobs, message=message )
+ return trans.fill_template( '/webapps/reports/jobs_tool_per_month.mako',
+ specified_date=specified_date,
+ tool_id=tool_id,
+ jobs=jobs,
+ message=message )
@web.expose
def tool_for_month( self, trans, **kwd ):
if 'operation' in kwd:
@@ -462,8 +492,7 @@ class Jobs( BaseController ):
action='job_info',
**kwd ) )
if operation == "tool_per_month":
- # The received id is the job id, so we need to get the id of the user
- # that submitted the job.
+ # The received id is the job id, so we need to get the jobs tool_id.
job_id = kwd.get( 'id', None )
job = get_job( trans, job_id )
kwd[ 'tool_id' ] = job.tool_id
@@ -497,7 +526,10 @@ class Jobs( BaseController ):
.one()
# TODO: for some reason the job_info.id is not the same as job_id in the template, so we need to pass job_id
# This needs to be fixed ASAP!
- return trans.fill_template( '/webapps/reports/job_info.mako', job_id=job_id, job_info=job_info, message=message )
+ return trans.fill_template( '/webapps/reports/job_info.mako',
+ job_id=job_id,
+ job_info=job_info,
+ message=message )
@web.expose
def per_domain( self, trans, **kwd ):
# TODO: rewrite using alchemy
--- a/templates/webapps/reports/system.mako
+++ b/templates/webapps/reports/system.mako
@@ -1,13 +1,17 @@
<%inherit file="/base.mako"/><%namespace file="/message.mako" import="render_msg" />
+<%
+ from galaxy.web.framework.helpers import time_ago
+%>
+
%if message:
${render_msg( message, 'done' )}
%endif
<div class="toolForm"><h3 align="center">Old Histories and Datasets</h3>
- <table align="center" width="70%" class="border" cellpadding="5" cellspacing="5">
+ <table align="center" width="90%" class="border" cellpadding="5" cellspacing="5"><tr><td><form method="post" action="system">
@@ -33,10 +37,14 @@
</td></tr></table>
- <br clear="left" /><br />
+ <br clear="left" /><h3 align="center">Current Disk Space Where Datasets are Stored</h3>
- <table align="center" width="60%" class="colored">
- <tr><td colspan="5"><div class="toolFormTitle">Disk Usage for ${file_path}</div></td></tr>
+ <table align="center" width="90%" class="colored">
+ <tr>
+ <td colspan="5">
+ <b>Disk Usage for ${file_path}</b>
+ </td>
+ </tr><tr class="header"><td>File System</td><td>Disk Size</td>
@@ -51,16 +59,16 @@
<td>${disk_usage[3]}</td><td>${disk_usage[4]}</td></tr>
- %if len( datasets ) == 0:
- <tr class="header"><td colspan="5">There are no datasets larger than ${file_size_str}</td></tr>
- %else:
- <tr><td colspan="5"><div class="toolFormTitle">${len( datasets )} largest datasets over ${file_size_str}</div></td></tr>
+ </table>
+ <br clear="left" />
+ %if datasets.count() > 0:
+ <h3 align="center">${datasets.count()} largest unpurged data files over ${file_size_str}</h3>
+ <table align="center" width="90%" class="colored"><tr class="header"><td>File</td><td>Last Updated</td>
- <td>History ID</td><td>Deleted</td>
- <td>Size on Disk</td>
+ <td>File Size</td></tr><% ctr = 0 %>
%for dataset in datasets:
@@ -69,14 +77,19 @@
%else:
<tr class="tr">
%endif
- <td>dataset_${dataset[0]}.dat</td>
- <td>${dataset[1]}</td>
- <td>${dataset[2]}</td>
- <td>${dataset[3]}</td>
- <td>${dataset[4]}</td>
+ <td>
+ <% dataset_label = 'dataset%d_.dat' % dataset.id %>
+ <a href="${h.url_for( controller='system', action='dataset_info', id=trans.security.encode_id( dataset.id ) )}">${dataset_label}</a>
+ </td>
+ <td>${time_ago( dataset.update_time )}</td>
+ <td>${dataset.deleted}</td>
+ <td>${dataset.file_size}</td></tr><% ctr += 1 %>
%endfor
- %endif
- </table>
+ </table>
+ <br clear="left" />
+ %else:
+ <h3 align="center">There are no unpurged data files larger than ${file_size_str}</h3>
+ %endif
</div>
--- /dev/null
+++ b/templates/webapps/reports/dataset_info.mako
@@ -0,0 +1,119 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<%
+ from galaxy.web.framework.helpers import time_ago
+ from galaxy.web.controllers.library_common import get_containing_library_from_library_dataset
+%>
+
+%if message:
+ ${render_msg( message, 'done' )}
+%endif
+
+<div class="toolForm">
+ <h3 align="center">Dataset Information</h3>
+ <div class="toolFormBody">
+ <div class="form-row">
+ <label>Date uploaded:</label>
+ ${time_ago( dataset.create_time )}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>Last updated:</label>
+ ${time_ago( dataset.update_time )}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>File size:</label>
+ ${dataset.get_size( nice_size=True )}
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <label>State:</label>
+ ${dataset.state}
+ <div style="clear: both"></div>
+ </div>
+ </div>
+</div>
+%if associated_hdas:
+ <p/>
+ <b>Active (undeleted) history items that use this library dataset's disk file</b>
+ <div class="toolForm">
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>History</th>
+ <th>History Item</th>
+ <th>Last Updated</th>
+ <th>User</th>
+ </tr>
+ </thead>
+ %for hda in associated_hdas:
+ <tr>
+ <td>${hda.history.get_display_name()}</td>
+ <td>${hda.get_display_name()}</td>
+ <td>${time_ago( hda.update_time )}</td>
+ <td>
+ %if hda.history.user:
+ ${hda.history.user.email}
+ %else:
+ anonymous
+ %endif
+ </td>
+ </tr>
+ %endfor
+ </table>
+ </div>
+ <p/>
+%endif
+%if associated_lddas:
+ <p/>
+ <b>Other active (undeleted) library datasets that use this library dataset's disk file</b>
+ <div class="toolForm">
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>Library</th>
+ <th>Folder</th>
+ <th>Library Dataset</th>
+ <th>Last Updated</th>
+ <th>Uploaded By</th>
+ </tr>
+ </thead>
+ %for ldda in associated_lddas:
+ <% containing_library = get_containing_library_from_library_dataset( trans, ldda.library_dataset ) %>
+ <tr>
+ <td>
+ <%
+ if containing_library:
+ library_display_name = containing_library.get_display_name()
+ else:
+ library_display_name = 'error finding library'
+ %>
+ ${library_display_name}
+ </td>
+ <td>
+ <%
+ library_dataset = ldda.library_dataset
+ folder = library_dataset.folder
+ folder_display_name = folder.get_display_name()
+ if folder_display_name == library_display_name:
+ folder_display_name = 'library root'
+ %>
+ ${folder_display_name}
+ </td>
+ <td>${ldda.get_display_name()}</td>
+ <td>${time_ago( ldda.update_time )}</td>
+ <td>
+ %if ldda.user:
+ ${ldda.user.email}
+ %else:
+ anonymous
+ %endif
+ </td>
+ </tr>
+ %endfor
+ </table>
+ </div>
+ <p/>
+%endif
--- a/templates/webapps/reports/jobs_per_user.mako
+++ b/templates/webapps/reports/jobs_per_user.mako
@@ -2,7 +2,7 @@
<%namespace file="/message.mako" import="render_msg" />
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -432,13 +432,19 @@ class Dataset( object ):
path = os.path.join( os.path.join( self.file_path, *directory_hash_id( self.id ) ), "dataset_%d_files" % self.id )
# Make path absolute
return os.path.abspath( path )
- def get_size( self ):
+ def get_size( self, nice_size=False ):
"""Returns the size of the data on disk"""
if self.file_size:
- return self.file_size
+ if nice_size:
+ return galaxy.datatypes.data.nice_size( self.file_size )
+ else:
+ return self.file_size
else:
try:
- return os.path.getsize( self.file_name )
+ if nice_size:
+ return galaxy.datatypes.data.nice_size( os.path.getsize( self.file_name ) )
+ else:
+ return os.path.getsize( self.file_name )
except OSError:
return 0
def set_size( self ):
--- a/templates/webapps/reports/jobs_specified_month_in_error.mako
+++ b/templates/webapps/reports/jobs_specified_month_in_error.mako
@@ -2,7 +2,7 @@
<%namespace file="/message.mako" import="render_msg" />
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
--- a/templates/webapps/reports/jobs_per_tool.mako
+++ b/templates/webapps/reports/jobs_per_tool.mako
@@ -2,7 +2,7 @@
<%namespace file="/message.mako" import="render_msg" />
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
--- a/templates/webapps/reports/users_last_access_date.mako
+++ b/templates/webapps/reports/users_last_access_date.mako
@@ -2,7 +2,7 @@
<%namespace file="/message.mako" import="render_msg" />
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
--- a/templates/webapps/reports/jobs_per_month_in_error.mako
+++ b/templates/webapps/reports/jobs_per_month_in_error.mako
@@ -2,7 +2,7 @@
<%namespace file="/message.mako" import="render_msg" />
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
@@ -24,7 +24,7 @@
%else:
<tr class="tr">
%endif
- <td><a href="${h.url_for( controller='jobs', action='specified_month_in_error', month=job[0] )}">${job[2]} ${job[3]}</a></td>
+ <td><a href="${h.url_for( controller='jobs', action='specified_month_in_error', specified_date=job[0]+'-01' )}">${job[2]} ${job[3]}</a></td><td>${job[1]}</td></tr><% ctr += 1 %>
--- a/lib/galaxy/webapps/reports/controllers/system.py
+++ b/lib/galaxy/webapps/reports/controllers/system.py
@@ -1,10 +1,6 @@
import operator, os
from datetime import datetime, timedelta
from galaxy.web.base.controller import *
-#import pkg_resources
-#pkg_resources.require( "SQLAlchemy >= 0.4" )
-#from sqlalchemy.orm import eagerload
-#from sqlalchemy import desc
from galaxy import model
from galaxy.model.orm import *
import logging
@@ -44,7 +40,6 @@ class System( BaseController ):
deleted_histories_days=deleted_histories_days,
deleted_datasets_days=deleted_datasets_days,
message=message )
-
def userless_histories( self, trans, **kwd ):
"""The number of userless histories and associated datasets that have not been updated for the specified number of days."""
params = util.Params( kwd )
@@ -54,11 +49,6 @@ class System( BaseController ):
cutoff_time = datetime.utcnow() - timedelta( days=userless_histories_days )
history_count = 0
dataset_count = 0
- #h = self.app.model.History
- #where = ( h.table.c.user_id==None ) & ( h.table.c.deleted=='f' ) & ( h.table.c.update_time < cutoff_time )
- #histories = h.query().filter( where ).options( eagerload( 'datasets' ) )
-
- #for history in histories:
for history in trans.sa_session.query( model.History ) \
.filter( and_( model.History.table.c.user_id == None,
model.History.table.c.deleted == True,
@@ -71,7 +61,6 @@ class System( BaseController ):
else:
message = "Enter the number of days."
return str( userless_histories_days ), message
-
def deleted_histories( self, trans, **kwd ):
"""
The number of histories that were deleted more than the specified number of days ago, but have not yet been purged.
@@ -104,7 +93,6 @@ class System( BaseController ):
else:
message = "Enter the number of days."
return str( deleted_histories_days ), message
-
def deleted_datasets( self, trans, **kwd ):
"""The number of datasets that were deleted more than the specified number of days ago, but have not yet been purged."""
params = util.Params( kwd )
@@ -128,6 +116,25 @@ class System( BaseController ):
else:
message = "Enter the number of days."
return str( deleted_datasets_days ), message
+ @web.expose
+ def dataset_info( self, trans, **kwd ):
+ params = util.Params( kwd )
+ message = ''
+ dataset = trans.sa_session.query( model.Dataset ).get( trans.security.decode_id( kwd.get( 'id', '' ) ) )
+ # Get all associated hdas and lddas that use the same disk file.
+ associated_hdas = trans.sa_session.query( trans.model.HistoryDatasetAssociation ) \
+ .filter( and_( trans.model.HistoryDatasetAssociation.deleted == False,
+ trans.model.HistoryDatasetAssociation.dataset_id == dataset.id ) ) \
+ .all()
+ associated_lddas = trans.sa_session.query( trans.model.LibraryDatasetDatasetAssociation ) \
+ .filter( and_( trans.model.LibraryDatasetDatasetAssociation.deleted == False,
+ trans.model.LibraryDatasetDatasetAssociation.dataset_id == dataset.id ) ) \
+ .all()
+ return trans.fill_template( '/webapps/reports/dataset_info.mako',
+ dataset=dataset,
+ associated_hdas=associated_hdas,
+ associated_lddas=associated_lddas,
+ message=message )
def get_disk_usage( self, file_path ):
df_cmd = 'df -h ' + file_path
is_sym_link = os.path.islink( file_path )
@@ -163,13 +170,13 @@ class System( BaseController ):
def disk_usage( self, trans, **kwd ):
file_path = trans.app.config.file_path
disk_usage = self.get_disk_usage( file_path )
- min_file_size = 2**32 # 4 Gb
+ #min_file_size = 2**32 # 4 Gb
+ min_file_size = 0
file_size_str = nice_size( min_file_size )
- datasets = []
- for dataset in trans.sa_session.query( model.Dataset ) \
- .filter( model.Dataset.table.c.file_size > min_file_size ) \
- .order_by( desc( model.Dataset.table.c.file_size ) ):
- datasets.append( ( dataset.id, str( dataset.update_time )[0:10], dataset.history.history_id, dataset.deleted, dataset.file_size ) )
+ datasets = trans.sa_session.query( model.Dataset ) \
+ .filter( and_( model.Dataset.table.c.purged == False,
+ model.Dataset.table.c.file_size > min_file_size ) ) \
+ .order_by( desc( model.Dataset.table.c.file_size ) )
return file_path, disk_usage, datasets, file_size_str
def nice_size( size ):
--- a/lib/galaxy/webapps/reports/controllers/users.py
+++ b/lib/galaxy/webapps/reports/controllers/users.py
@@ -13,14 +13,12 @@ log = logging.getLogger( __name__ )
class Users( BaseController ):
@web.expose
def registered_users( self, trans, **kwd ):
- params = util.Params( kwd )
- message = params.get( 'message', '' )
+ message = util.restore_text( kwd.get( 'message', '' ) )
num_users = trans.sa_session.query( galaxy.model.User ).count()
return trans.fill_template( '/webapps/reports/registered_users.mako', num_users=num_users, message=message )
@web.expose
def registered_users_per_month( self, trans, **kwd ):
- params = util.Params( kwd )
- message = params.get( 'message', '' )
+ message = util.restore_text( kwd.get( 'message', '' ) )
q = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( galaxy.model.User.table.c.create_time ) ).label( 'date' ),
sa.func.count( galaxy.model.User.table.c.id ).label( 'num_users' ) ),
from_obj = [ galaxy.model.User.table ],
@@ -29,15 +27,19 @@ class Users( BaseController ):
users = []
for row in q.execute():
users.append( ( row.date.strftime( "%Y-%m" ),
- row.num_users,
- row.date.strftime( "%B" ),
- row.date.strftime( "%Y" ) ) )
- return trans.fill_template( '/webapps/reports/registered_users_per_month.mako', users=users, message=message )
+ row.num_users,
+ row.date.strftime( "%B" ),
+ row.date.strftime( "%Y" ) ) )
+ return trans.fill_template( '/webapps/reports/registered_users_per_month.mako',
+ users=users,
+ message=message )
@web.expose
def specified_month( self, trans, **kwd ):
- params = util.Params( kwd )
- message = params.get( 'message', '' )
- year, month = map( int, params.get( 'month', datetime.utcnow().strftime( "%Y-%m" ) ).split( "-" ) )
+ message = util.restore_text( kwd.get( 'message', '' ) )
+ # If specified_date is not received, we'll default to the current month
+ specified_date = kwd.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
+ specified_month = specified_date[ :7 ]
+ year, month = map( int, specified_month.split( "-" ) )
start_date = date( year, month, 1 )
end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
month_label = start_date.strftime( "%B" )
@@ -63,9 +65,10 @@ class Users( BaseController ):
message=message )
@web.expose
def specified_date( self, trans, **kwd ):
- params = util.Params( kwd )
- message = params.get( 'message', '' )
- year, month, day = map( int, params.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) ).split( "-" ) )
+ message = util.restore_text( kwd.get( 'message', '' ) )
+ # If specified_date is not received, we'll default to the current month
+ specified_date = kwd.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
+ year, month, day = map( int, specified_date.split( "-" ) )
start_date = date( year, month, day )
end_date = start_date + timedelta( days=1 )
day_of_month = start_date.strftime( "%d" )
@@ -91,9 +94,8 @@ class Users( BaseController ):
message=message )
@web.expose
def last_access_date( self, trans, **kwd ):
- params = util.Params( kwd )
- message = params.get( 'message', '' )
- not_logged_in_for_days = params.get( 'not_logged_in_for_days', 90 )
+ message = util.restore_text( kwd.get( 'message', '' ) )
+ not_logged_in_for_days = kwd.get( 'not_logged_in_for_days', 90 )
if not not_logged_in_for_days:
not_logged_in_for_days = 0
cutoff_time = datetime.utcnow() - timedelta( days=int( not_logged_in_for_days ) )
--- a/templates/webapps/reports/registered_users_specified_month.mako
+++ b/templates/webapps/reports/registered_users_specified_month.mako
@@ -24,7 +24,7 @@
%else:
<tr class="tr">
%endif
- <td><a href="${h.url_for( controller='users', action='specified_date', specified_date=user[0], day_label=user[3], month_label=month_label, year_label=year_label, day_of_month=user[1] )}">${user[3]}, ${month_label} ${user[1]}, ${year_label}</a></td>
+ <td><a href="${h.url_for( controller='users', action='specified_date', specified_date=user[0] )}">${user[3]}, ${month_label} ${user[1]}, ${year_label}</a></td><td>${user[2]}</td></tr><% ctr += 1 %>
--- a/templates/webapps/reports/index.mako
+++ b/templates/webapps/reports/index.mako
@@ -73,14 +73,14 @@
</div><div class="toolSectionBody"><div class="toolSectionBg">
- <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='today_all' )}">Number of jobs today</a></div>
- <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='specified_month_all' )}">Number of jobs per day for current month</a></div>
- <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='specified_month_in_error' )}">Number of jobs in error per day for current month</a></div>
+ <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='today_all' )}">Today's jobs</a></div>
+ <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='specified_month_all' )}">Jobs per day this month</a></div>
+ <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='specified_month_in_error' )}">Jobs in error per day this month</a></div><div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='all_unfinished' )}">All unfinished jobs</a></div>
- <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='per_month_all' )}">Number of jobs per month</a></div>
- <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='per_month_in_error' )}">Number of jobs in error per month</a></div>
- <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='per_user' )}">Number of jobs per user</a></div>
- <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='per_tool' )}">Number of jobs per tool</a></div>
+ <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='per_month_all' )}">Jobs per month</a></div>
+ <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='per_month_in_error' )}">Jobs in error per month</a></div>
+ <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='per_user' )}">Jobs per user</a></div>
+ <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='jobs', action='per_tool' )}">Jobs per tool</a></div></div></div><div class="toolSectionPad"></div>
@@ -101,7 +101,7 @@
</div><div class="toolSectionBody"><div class="toolSectionBg">
- <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='system', action='index' )}">Disk space, old histories and datasets</a></div>
+ <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='system', action='index' )}">Disk space maintenance</a></div></div></div></div>
@@ -110,6 +110,6 @@
</%def><%def name="center_panel()">
- <% center_url = h.url_for( controller='jobs', action='today_all' ) %>
+ <% center_url = h.url_for( controller='jobs', action='specified_month_all' ) %><iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${center_url}"></iframe></%def>
--- a/templates/webapps/reports/jobs_per_domain.mako
+++ b/templates/webapps/reports/jobs_per_domain.mako
@@ -2,7 +2,7 @@
<%namespace file="/message.mako" import="render_msg" />
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
--- a/lib/galaxy/web/controllers/library_common.py
+++ b/lib/galaxy/web/controllers/library_common.py
@@ -1904,15 +1904,14 @@ def branch_deleted( folder ):
def get_containing_library_from_library_dataset( trans, library_dataset ):
"""Given a library_dataset, get the containing library"""
folder = library_dataset.folder
- parent = folder
while folder.parent:
- parent = folder.parent
- # We have parent set to the library's root folder, which has the
- # same name as the library
+ folder = folder.parent
+ # We have folder set to the library's root folder, which has the same name as the library
for library in trans.sa_session.query( trans.model.Library ) \
.filter( and_( trans.model.Library.table.c.deleted == False,
- trans.model.Library.table.c.name == parent.name ) ):
- if library.root_folder == parent:
+ trans.model.Library.table.c.name == folder.name ) ):
+ # Just to double-check
+ if library.root_folder == folder:
return library
return None
--- a/templates/webapps/reports/jobs_tool_per_month.mako
+++ b/templates/webapps/reports/jobs_tool_per_month.mako
@@ -2,7 +2,7 @@
<%namespace file="/message.mako" import="render_msg" />
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
@@ -25,7 +25,7 @@
<tr class="tr">
%endif
<td>${job[2]} ${job[3]}</td>
- <td><a href="${h.url_for( controller='jobs', action='tool_for_month', tool_id=tool_id, month=job[0] )}">${job[1]}</a></td>
+ <td><a href="${h.url_for( controller='jobs', action='tool_for_month', tool_id=tool_id, specified_date=job[0]+'-01' )}">${job[1]}</a></td></tr><% ctr += 1 %>
%endfor
--- a/templates/webapps/reports/registered_users_per_month.mako
+++ b/templates/webapps/reports/registered_users_per_month.mako
@@ -24,7 +24,7 @@
%else:
<tr class="tr">
%endif
- <td><a href="${h.url_for( controller='users', action='specified_month', month=user[0], month_label=user[2].strip(), year_label=user[3] )}">${user[2]} ${user[3]}</a></td>
+ <td><a href="${h.url_for( controller='users', action='specified_month', specified_date=user[0]+'-01' )}">${user[2]} ${user[3]}</a></td><td>${user[1]}</td></tr><% ctr += 1 %>
--- a/templates/webapps/reports/jobs_specified_month_all.mako
+++ b/templates/webapps/reports/jobs_specified_month_all.mako
@@ -2,7 +2,7 @@
<%namespace file="/message.mako" import="render_msg" />
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
--- a/templates/webapps/reports/jobs_per_month_all.mako
+++ b/templates/webapps/reports/jobs_per_month_all.mako
@@ -2,7 +2,7 @@
<%namespace file="/message.mako" import="render_msg" />
%if message:
- ${render_msg( message, status )}
+ ${render_msg( message, 'done' )}
%endif
<div class="toolForm">
@@ -26,7 +26,7 @@
%else:
<tr class="tr">
%endif
- <td><a href="${h.url_for( controller='jobs', action='specified_month_all', month=job[0] )}">${job[4]} ${job[5]}</a></td>
+ <td><a href="${h.url_for( controller='jobs', action='specified_month_all', specified_date=job[0]+'-01' )}">${job[4]} ${job[5]}</a></td><td>${job[1]}</td><td>${job[2]}</td><td>${job[3]}</td>
1
0
galaxy-dist commit 6dde140d0cfd: I forgot to change the disk file size from 0 back to 4 gb for the systems report before may last commit.
by commits-noreply@bitbucket.org 07 Jun '10
by commits-noreply@bitbucket.org 07 Jun '10
07 Jun '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1275676257 14400
# Node ID 6dde140d0cfd53820f9cbb83bbb44338ac8bd6aa
# Parent a76d05bb41e1c1f1eeaa93a18289eeed1213199b
I forgot to change the disk file size from 0 back to 4 gb for the systems report before may last commit.
--- a/lib/galaxy/webapps/reports/controllers/system.py
+++ b/lib/galaxy/webapps/reports/controllers/system.py
@@ -170,8 +170,7 @@ class System( BaseController ):
def disk_usage( self, trans, **kwd ):
file_path = trans.app.config.file_path
disk_usage = self.get_disk_usage( file_path )
- #min_file_size = 2**32 # 4 Gb
- min_file_size = 0
+ min_file_size = 2**32 # 4 Gb
file_size_str = nice_size( min_file_size )
datasets = trans.sa_session.query( model.Dataset ) \
.filter( and_( model.Dataset.table.c.purged == False,
1
0