| %s.%s | ' % ( str( i+1 ), name ) ) - if dataset.metadata.columns - len( self.column_names ) > 0: - for i in range( len( self.column_names ), dataset.metadata.columns ): - out.append( '%s | ' % str( i+1 ) ) - out.append( '
|---|
| %s.Chrom | ' % i ) - elif i == dataset.metadata.startCol: - out.append( '%s.Start | ' % i ) - elif i == dataset.metadata.endCol: - out.append( '%s.End | ' % i ) - elif dataset.metadata.strandCol and i == dataset.metadata.strandCol: - out.append( '%s.Strand | ' % i ) - elif dataset.metadata.nameCol and i == dataset.metadata.nameCol: - out.append( '%s.Name | ' % i ) - else: - out.append( '%s | ' % i ) - out.append('
|---|
| %s.%s | ' % ( str( i+1 ), name ) ) - out.append( self.make_html_peek_rows( dataset, skipchars=skipchars ) ) - out.append( '
|---|
| %s | ' % str( i ) ) - out.append( '
|---|
| %s.%s | ' % ( str( i+1 ), name ) ) - # This data type requires at least 24 columns in the data - if dataset.metadata.columns - len( self.column_names ) > 0: - for i in range( len( self.column_names ), dataset.metadata.columns ): - out.append( '%s | ' % str( i+1 ) ) - out.append( '
|---|
| %s.%s | ' % ( str( i+1 ), name ) ) - # This data type requires at least 11 columns in the data - if dataset.metadata.columns - len( self.column_names ) > 0: - for i in range( len( self.column_names ), dataset.metadata.columns ): - out.append( '%s | ' % str( i+1 ) ) - out.append( '
|---|
| %s.Chrom | ' % i ) - elif i == dataset.metadata.startCol: - out.append( '%s.Start | ' % i ) - elif i == dataset.metadata.baseCol: - out.append( '%s.Base | ' % i ) - else: - out.append( '%s | ' % i ) - out.append('
|---|
| %s.%s | ' % ( str( i+1 ), name ) ) - out.append( self.make_html_peek_rows( dataset, skipchars=skipchars ) ) - out.append( '
|---|
- This installation of Galaxy has been configured such that only users who are logged in may use it.%s + This %s has been configured such that only users who are logged in may use it.%s
""" -require_login_nocreation_template = require_login_template % "" -require_login_creation_template = require_login_template % " If you don't already have an account, you may create one." OPENID_PROVIDERS = { 'Google' : 'https://www.google.com/accounts/o8/id', 'Yahoo!' : 'http://yahoo.com', @@ -368,9 +364,17 @@ class User( BaseUIController, UsesFormDefinitions ): redirect_url = url_for( '/' ) if not user and trans.app.config.require_login: if trans.app.config.allow_user_creation: - header = require_login_creation_template % web.url_for( action='create', cntrller='user' ) + create_account_str = " If you don't already have an account, you may create one." % \ + web.url_for( action='create', cntrller='user', webapp=webapp ) + if webapp == 'galaxy': + header = require_login_template % ( "Galaxy instance", create_account_str ) + else: + header = require_login_template % ( "Galaxy tool shed", create_account_str ) else: - header = require_login_nocreation_template + if webapp == 'galaxy': + header = require_login_template % ( "Galaxy instance", "" ) + else: + header = require_login_template % ( "Galaxy tool shed", "" ) return trans.fill_template( '/user/login.mako', webapp=webapp, email=email, @@ -405,11 +409,12 @@ class User( BaseUIController, UsesFormDefinitions ): status = 'error' else: trans.handle_user_login( user, webapp ) - trans.log_event( "User logged in" ) - message = 'You are now logged in as %s."+ai.message+"",{Close:hide_modal})});ah.content_div.append(aj)}}else{if(ai==="no converter"){ah.container_div.addClass("error");ah.content_div.text(L)}else{if(ai==="no data"||(ai.data!==undefined&&(ai.data===null||ai.data.length===0))){ah.container_div.addClass("nodata");ah.content_div.text(G)}else{if(ai==="pending"){ah.container_div.addClass("pending");ah.content_div.text(u);setTimeout(function(){ah.init()},ah.data_query_wait)}else{if(ai.status==="data"){if(ai.valid_chroms){ah.valid_chroms=ai.valid_chroms;ah.make_name_popup_menu()}ah.content_div.text(ab);if(ah.view.chrom){ah.content_div.text("");ah.content_div.css("height",ah.height_px+"px");ah.enabled=true;$.when(ah.predraw_init()).done(function(){ah.container_div.removeClass("nodata error pending");ah.request_draw()})}}}}}}})},predraw_init:function(){},});var O=function(ao,am){var ai=this,ap=ai.view;n(ai.container_div,ai.drag_handle_class,".group",ai);this.filters_manager=new ac(this,(ao!==undefined?ao:{}));this.filters_available=false;this.filters_visible=false;this.tool=(am!==undefined&&obj_length(am)>0?new s(this,am):undefined);this.is_overview=false;if(ai.hidden){return}if(this.filters_manager){this.filters_div=this.filters_manager.parent_div;this.header_div.after(this.filters_div)}if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}if(ai.display_modes!==undefined){if(ai.mode_div===undefined){ai.mode_div=$("").appendTo(ai.header_div);var aj=(ai.config&&ai.config.values.mode?ai.config.values.mode:ai.display_modes[0]);ai.mode=aj;ai.mode_div.text(aj);var ah={};for(var ak=0,an=ai.display_modes.length;ak
D){Q=true;E=D}}if(I==="Histogram"){E=Math.round(E/J*z);N.fillRect(R,U,C,-E)}else{if(I==="Intensity"){E=255-Math.floor((E-H)/J*255);N.fillStyle="rgb("+E+","+E+","+E+")";N.fillRect(R,0,C,z)}else{E=Math.round(z-(E-H)/J*z);if(F){N.lineTo(R,E)}else{F=true;if(I==="Filled"){N.moveTo(R,z);N.lineTo(R,E)}else{N.moveTo(R,E)}}}}N.fillStyle=this.prefs.overflow_color;if(Q||G){var S;if(I==="Histogram"||I==="Intensity"){S=C}else{R-=2;S=4}if(Q){N.fillRect(R,0,S,3)}if(G){N.fillRect(R,z-3,S,3)}}N.fillStyle=this.prefs.color}if(I==="Filled"){if(F){N.lineTo(R,U);N.lineTo(0,U)}N.fill()}else{N.stroke()}N.restore()};var o=function(B,D,y,A,C,z){n.call(this,B,D,y,A,C);this.alpha_generator=(z?z:new g())};o.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};u(o.prototype,{get_required_height:function(z){var y=y_scale=this.get_row_height(),A=this.mode;if(A==="no_detail"||A==="Squish"||A==="Pack"){y=z*y_scale}return y+Math.max(Math.round(y_scale/2),5)},draw:function(K,B,J,G){var E=this.data,H=this.view_start,L=this.view_end;K.save();K.fillStyle=this.prefs.block_color;K.textAlign="right";var O=this.view_end-this.view_start,N=B/O,A=this.get_row_height();for(var D=0,F=E.length;D D){Q=true;E=D}}if(I==="Histogram"){E=Math.round(E/J*z);N.fillRect(R,U,C,-E)}else{if(I==="Intensity"){E=255-Math.floor((E-H)/J*255);N.fillStyle="rgb("+E+","+E+","+E+")";N.fillRect(R,0,C,z)}else{E=Math.round(z-(E-H)/J*z);if(F){N.lineTo(R,E)}else{F=true;if(I==="Filled"){N.moveTo(R,z);N.lineTo(R,E)}else{N.moveTo(R,E)}}}}N.fillStyle=this.prefs.overflow_color;if(Q||G){var S;if(I==="Histogram"||I==="Intensity"){S=C}else{R-=2;S=4}if(Q){N.fillRect(R,0,S,3)}if(G){N.fillRect(R,z-3,S,3)}}N.fillStyle=this.prefs.color}if(I==="Filled"){if(F){N.lineTo(R,U);N.lineTo(0,U)}N.fill()}else{N.stroke()}N.restore()};var m=function(y){this.feature_positions={};this.slot_height=y;this.translation=0;this.y_translation=0};m.prototype.map_feature_data=function(z,B,y,A){if(!this.feature_positions[B]){this.feature_positions[B]=[]}this.feature_positions[B].push({data:z,x_start:y,x_end:A})};m.prototype.get_feature_data=function(z,D){var C=Math.floor((D-this.y_translation)/this.slot_height),B;if(!this.feature_positions[C]){return null}z+=this.translation;for(var A=0;A
named:
"),av,au,ay;for(av in at){au=at[av];ay=$("
").appendTo(ax);$(" ").appendTo(ay).text(av);$(" ").attr("align","left").appendTo(ay).text(typeof(au)=="number"?Z(au,2):au)}ai.append($(" "+ag.message+"
",{Close:hide_modal})});af.content_div.append(ah)}}else{if(ag==="no converter"){af.container_div.addClass("error");af.content_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){af.container_div.addClass("nodata");af.content_div.text(D)}else{if(ag==="pending"){af.container_div.addClass("pending");af.content_div.text(t);setTimeout(function(){af.init()},af.data_query_wait)}else{if(ag.status==="data"){if(ag.valid_chroms){af.valid_chroms=ag.valid_chroms;af.update_icons()}af.content_div.text(Y);if(af.view.chrom){af.content_div.text("");af.content_div.css("height",af.height_px+"px");af.enabled=true;$.when(af.predraw_init()).done(function(){af.container_div.removeClass("nodata error pending");af.request_draw()})}}}}}}});this.update_icons()},predraw_init:function(){}});var M=function(aj,ah,ag,ai,am,al,ak){i.call(this,aj,ah,ag,ai,ak);var af=this,ah=af.view;m(af.container_div,af.drag_handle_class,".group",af);this.filters_manager=new aa(this,(am!==undefined?am:{}));this.filters_available=false;this.filters_visible=false;this.tool=(al!==undefined&&obj_length(al)>0?new r(this,al):undefined);this.tile_cache=new c(R);if(this.header_div){if(this.filters_manager){this.filters_div=this.filters_manager.parent_div;this.header_div.after(this.filters_div)}if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}}};p(M.prototype,q.prototype,i.prototype,{copy:function(af){var ag=new this.constructor(this.name,this.view,af,this.hda_ldda,this.dataset_id,this.prefs,this.filters,this.tool,this.data_manager);ag.enabled=this.enabled;return ag},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,}},from_dict:function(ah,ag){var af=new this.constructor(ah.name,view,ag,ah.hda_ldda,ah.dataset_id,ah.prefs,ah.filters,ah.tool);if(ah.mode){af.change_mode(ah.mode)}return af},change_mode:function(ag){var af=this;af.mode=ag;af.config.values.mode=ag;af.tile_cache.clear();af.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+af.mode+")");return af},update_icons:function(){var af=this;if(af.filters_available){af.action_icons.filters_icon.show()}else{af.action_icons.filters_icon.hide()}if(af.tool){af.action_icons.tools_icon.show()}else{af.action_icons.tools_icon.hide()}},_gen_tile_cache_key:function(ag,ah,af){return ag+"_"+ah+"_"+af},request_draw:function(ag,af){this.view.request_redraw(false,ag,af,this)},_draw:function(ah,ar){if(!this.can_draw()){return}var ap=this.view.low,al=this.view.high,an=al-ap,ai=this.view.container.width(),av=ai/an,ak=this.view.resolution,au=this.content_div;if(this.is_overview){ap=this.view.max_low;al=this.view.max_high;ak=Math.pow(A,Math.ceil(Math.log((view.max_high-view.max_low)/Q)/Math.log(A)));av=ai/(view.max_high-view.max_low)}if(!ar){this.content_div.children().addClass("remove")}this.max_height=0;var ag=Math.floor(ap/ak/Q);var ao=true;var at=[];var af=0;var am=function(aw){return("track" in aw)};while((ag*Q*ak)"),
+ key, value, row;
+ for (key in feature_dict) {
+ value = feature_dict[key];
+ row = $("
").appendTo(table);
+ $(" ").appendTo(row).text(key);
+ $(" ").attr("align", "left").appendTo(row)
+ .text(typeof(value) == 'number' ? round(value, 2) : value);
+ }
+ popup.append( $(" " + result.message + "
", { "Close" : hide_modal } );
});
@@ -2230,7 +2811,7 @@ extend(Track.prototype, Drawable.prototype, {
} else if (result['status'] === "data") {
if (result['valid_chroms']) {
track.valid_chroms = result['valid_chroms'];
- track.make_name_popup_menu();
+ track.update_icons();
}
track.content_div.text(DATA_OK);
if (track.view.chrom) {
@@ -2245,14 +2826,18 @@ extend(Track.prototype, Drawable.prototype, {
}
}
});
+
+ this.update_icons();
},
/**
* Additional initialization required before drawing track for the first time.
*/
- predraw_init: function() {},
+ predraw_init: function() {}
});
-var TiledTrack = function(filters_list, tool_dict) {
+var TiledTrack = function(name, view, container, prefs, filters_list, tool_dict, data_manager) {
+ Track.call(this, name, view, container, prefs, data_manager);
+
var track = this,
view = track.view;
@@ -2265,57 +2850,43 @@ var TiledTrack = function(filters_list, tool_dict) {
this.filters_available = false;
this.filters_visible = false;
this.tool = (tool_dict !== undefined && obj_length(tool_dict) > 0 ? new Tool(this, tool_dict) : undefined);
- this.is_overview = false;
+ this.tile_cache = new Cache(TILE_CACHE_SIZE);
- if (track.hidden) { return; }
+ if (this.header_div) {
+ //
+ // Create filters div.
+ //
+ if (this.filters_manager) {
+ this.filters_div = this.filters_manager.parent_div
+ this.header_div.after(this.filters_div);
+ }
- //
- // Create filters div.
- //
- if (this.filters_manager) {
- this.filters_div = this.filters_manager.parent_div
- this.header_div.after(this.filters_div);
- }
-
- //
- // Create dynamic tool div.
- //
- if (this.tool) {
- this.dynamic_tool_div = this.tool.parent_div;
- this.header_div.after(this.dynamic_tool_div);
- }
-
- //
- // Create modes control.
- //
- if (track.display_modes !== undefined) {
- if (track.mode_div === undefined) {
- track.mode_div = $("").appendTo(track.header_div);
- var init_mode = (track.config && track.config.values['mode'] ?
- track.config.values['mode'] : track.display_modes[0]);
- track.mode = init_mode;
- track.mode_div.text(init_mode);
-
- var mode_mapping = {};
- for (var i = 0, len = track.display_modes.length; i < len; i++) {
- var mode = track.display_modes[i];
- mode_mapping[mode] = function(mode) {
- return function() { track.change_mode(mode); };
- }(mode);
- }
- make_popupmenu(track.mode_div, mode_mapping);
- } else {
- track.mode_div.hide();
+ //
+ // Create dynamic tool div.
+ //
+ if (this.tool) {
+ this.dynamic_tool_div = this.tool.parent_div;
+ this.header_div.after(this.dynamic_tool_div);
}
}
-
- this.make_name_popup_menu();
};
extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
/**
- * Convert track to JSON object.
+ * Returns a copy of the track. The copy uses the same data manager so that the tracks can share data.
*/
- to_json: function() {
+ copy: function(container) {
+ // Create copy.
+ var new_track = new this.constructor(this.name, this.view, container, this.hda_ldda, this.dataset_id, this.prefs,
+ this.filters, this.tool, this.data_manager);
+ // Misc. init and return.
+ new_track.enabled = this.enabled;
+ return new_track;
+ },
+ /**
+ * Returns representation of object in a dictionary for easy saving.
+ * Use from_dict to recreate object.
+ */
+ to_dict: function() {
return {
"track_type": this.get_type(),
"name": this.name,
@@ -2325,101 +2896,57 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
"mode": this.mode,
};
},
+ /**
+ * Restore object from a dictionary created by to_dict()
+ */
+ from_dict: function(track_dict, container) {
+ var track = new this.constructor(
+ track_dict.name, view, container, track_dict.hda_ldda, track_dict.dataset_id,
+ track_dict.prefs, track_dict.filters, track_dict.tool);
+ if (track_dict.mode) {
+ track.change_mode(track_dict.mode);
+ }
+ return track;
+ },
/**
* Change track's mode.
*/
- change_mode: function(name) {
+ change_mode: function(new_mode) {
var track = this;
- track.mode_div.text(name);
// TODO: is it necessary to store the mode in two places (.mode and track_config)?
- track.mode = name;
- track.config.values['mode'] = name;
+ track.mode = new_mode;
+ track.config.values['mode'] = new_mode;
track.tile_cache.clear();
track.request_draw();
+ this.action_icons.mode_icon.attr("title", "Set display mode (now: " + track.mode + ")");
return track;
},
/**
- * Make popup menu for track name.
+ * Update track's buttons.
*/
- make_name_popup_menu: function() {
+ update_icons: function() {
var track = this;
- var track_dropdown = {};
-
//
- // Make track overview option.
+ // Show/hide filter icon.
//
- track_dropdown[(this.is_overview ? "Hide overview" : "Set as overview")] = function() {
- if (track.is_overview) {
- track.view.reset_overview();
- }
- else {
- track.view.set_overview(track);
- }
- };
-
- //
- // Edit config option.
- //
- track_dropdown["Edit configuration"] = function() {
- var cancel_fn = function() { hide_modal(); $(window).unbind("keypress.check_enter_esc"); },
- ok_fn = function() {
- track.config.update_from_form( $(".dialog-box") );
- hide_modal();
- $(window).unbind("keypress.check_enter_esc");
- },
- check_enter_esc = function(e) {
- if ((e.keyCode || e.which) === 27) { // Escape key
- cancel_fn();
- } else if ((e.keyCode || e.which) === 13) { // Enter key
- ok_fn();
- }
- };
-
- $(window).bind("keypress.check_enter_esc", check_enter_esc);
- show_modal("Configure Track", track.config.build_form(), {
- "Cancel": cancel_fn,
- "OK": ok_fn
- });
- };
-
- //
- // Show/hide filters option.
- //
- if (track.filters_available > 0) {
- // Show/hide filters menu item.
- var text = (track.filters_div.is(":visible") ? "Hide filters" : "Show filters");
- track_dropdown[text] = function() {
- // Toggle filtering div, reset filters, and remake menu.
- track.filters_visible = (track.filters_div.is(":visible"));
- if (track.filters_visible) {
- track.filters_manager.reset_filters();
- }
- track.filters_div.toggle();
- track.make_name_popup_menu();
- };
+ if (track.filters_available) {
+ track.action_icons.filters_icon.show();
+ }
+ else {
+ track.action_icons.filters_icon.hide();
}
//
- // Show/hide tool option.
+ // Show/hide tool icon.
//
if (track.tool) {
- // Show/hide dynamic tool menu item.
- var text = (track.dynamic_tool_div.is(":visible") ? "Hide tool" : "Show tool");
- track_dropdown[text] = function() {
- // Set track name, toggle tool div, and remake menu.
- if (!track.dynamic_tool_div.is(":visible")) {
- track.set_name(track.name + track.tool_region_and_parameters_str());
- }
- else {
- menu_option_text = "Show dynamic tool";
- track.revert_name();
- }
- track.dynamic_tool_div.toggle();
- track.make_name_popup_menu();
- };
+ track.action_icons.tools_icon.show();
}
-
+ else {
+ track.action_icons.tools_icon.hide();
+ }
+
//
// List chrom/contigs with data option.
//
@@ -2430,61 +2957,6 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
};
}
*/
-
- //
- // Remove option.
- //
- track_dropdown.Remove = function() {
- track.remove();
- };
-
- make_popupmenu(track.name_div, track_dropdown);
- },
- /**
- * Set track's overview status.
- */
- set_is_overview: function(is_overview) {
- this.is_overview = is_overview;
- this.make_name_popup_menu();
- },
- /**
- * Returns a jQuery Deferred object that resolves to a Tile with track's overview.
- * TODO: this should be the approach used when drawing any tile so that tile drawing is not blocking.
- */
- get_overview_tile: function() {
- var
- track = this;
- view = track.view,
- resolution = Math.pow(RESOLUTION, Math.ceil( Math.log( (view.max_high - view.max_low) / DENSITY ) / Math.log(RESOLUTION) )),
- view_width = view.container.width(),
- // w_scale units are pixels per base.
- w_scale = view_width / (view.max_high - view.max_low),
- overview_tile = $.Deferred();
- $.when(track.data_manager.get_data(view.max_low, view.max_high, "Auto", resolution, track.data_url_extra_params)).then(function(overview_data) {
- var
- key = track._gen_tile_cache_key(view_width, w_scale, 0),
- tile = track.tile_cache.get(key);
-
- // Draw tile if necessary.
- if (!tile) {
- tile = track.draw_tile(overview_data, "Auto", resolution, 0, w_scale);
- track.tile_cache.set(key, tile);
- }
-
- // Always copy tile because it may need to be used in viz.
- var
- src_canvas = $(tile.canvas.find("canvas")),
- new_canvas = src_canvas.clone(),
- src_ctx = src_canvas.get(0).getContext("2d"),
- tgt_ctx = new_canvas.get(0).getContext("2d"),
- data = src_ctx.getImageData(0, 0, src_ctx.canvas.width, src_ctx.canvas.height);
- // Need to undo offsets when placing image data.
- tgt_ctx.putImageData(data, -track.left_offset, (tile.data.dataset_type === "summary_tree" ? SUMMARY_TREE_TOP_PADDING : 0));
- new_tile = new Tile(-1, resolution, new_canvas);
- overview_tile.resolve(new_tile);
- });
-
- return overview_tile;
},
/**
* Generate a key for the tile cache.
@@ -2506,10 +2978,7 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
* can manage drawing.
*/
_draw: function(force, clear_after) {
- if (!this.enabled) { return; }
-
- // HACK: ReferenceTrack can draw without dataset ID, but other tracks cannot.
- if ( !(this instanceof ReferenceTrack) && (!this.dataset_id) ) { return; }
+ if ( !this.can_draw() ) { return; }
var low = this.view.low,
high = this.view.high,
@@ -2518,10 +2987,29 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
// w_scale units are pixels per base.
w_scale = width / range,
resolution = this.view.resolution,
- parent_element = $("");
+ // FIXME: parent element is not currently needed, but it may be useful for multitrack drawing.
+ parent_element = this.content_div;
+
+ // For overview, adjust high, low, resolution, and w_scale.
+ if (this.is_overview) {
+ low = this.view.max_low;
+ high = this.view.max_high;
+ resolution = Math.pow(RESOLUTION, Math.ceil( Math.log( (view.max_high - view.max_low) / DENSITY ) / Math.log(RESOLUTION) ));
+ w_scale = width / (view.max_high - view.max_low);
+ }
+
+ //
+ // Method for moving and/or removing tiles:
+ // (a) mark all elements for removal using class 'remove'
+ // (b) during tile drawing/placement, remove class for elements that are moved;
+ // this occurs in show_tile()
+ // (c) after drawing all tiles, remove elements still marked for removal
+ // (i.e. that still have class 'remove').
+ //
- if (!clear_after) { this.content_div.children().remove(); }
- this.content_div.append( parent_element );
+ // Step (a) for (re)moving tiles.
+ if (!clear_after) { this.content_div.children().addClass("remove"); }
+
this.max_height = 0;
// Index of first tile that overlaps visible region
var tile_index = Math.floor( low / resolution / DENSITY );
@@ -2529,17 +3017,21 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
var all_tiles_drawn = true;
var drawn_tiles = [];
var tile_count = 0;
+ var is_tile = function(o) { return (o && 'track' in o) };
// Draw or fetch and show tiles.
while ( ( tile_index * DENSITY * resolution ) < high ) {
- tile = this.draw_helper( force, width, tile_index, resolution, parent_element, w_scale );
- if ( tile ) {
- drawn_tiles.push( tile );
+ var draw_result = this.draw_helper( force, width, tile_index, resolution, parent_element, w_scale );
+ if ( is_tile(draw_result) ) {
+ drawn_tiles.push( draw_result );
} else {
all_tiles_drawn = false;
}
tile_index += 1;
tile_count++;
}
+
+ // Step (c) for (re)moving tiles.
+ if (!clear_after) { this.content_div.children(".remove").remove(); }
// Use interval to check if tiles have been drawn. When all tiles are drawn, call post-draw actions.
var track = this;
@@ -2570,16 +3062,16 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
tile = tiles[tile_index];
if (!tile.message) {
// Need to align with other tile(s) that have message(s).
- tile.canvas.css("padding-top", ERROR_PADDING);
+ tile.html_elt.css("padding-top", ERROR_PADDING);
}
}
}
},
/**
- * Handle a single tile, either from cache or by setting up a deferred
- * operation and then requesting another redraw
+ * Retrieves from cache, draws, or sets up drawing for a single tile. Returns either a Tile object or a
+ * jQuery.Deferred object that is fulfilled when tile can be drawn again.
*/
- draw_helper: function(force, width, tile_index, resolution, parent_element, w_scale, drawn_tiles, more_tile_data) {
+ draw_helper: function(force, width, tile_index, resolution, parent_element, w_scale, more_tile_data) {
var track = this,
key = this._gen_tile_cache_key(width, w_scale, tile_index),
tile_low = tile_index * DENSITY * resolution,
@@ -2595,7 +3087,7 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
// Helper to determine if object is jQuery deferred
var is_deferred = function ( d ) {
return ( 'isResolved' in d );
- }
+ };
// Flag to track whether we can draw everything now
var can_draw_now = true
@@ -2615,85 +3107,101 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
}
}
- // If we can draw now, do so
+ // If we can draw now, do so.
if ( can_draw_now ) {
- extend( tile_data, more_tile_data );
- var tile = track.draw_tile(tile_data, track.mode, resolution, tile_index, w_scale, seq_data);
- track.tile_cache.set(key, tile);
- // Don't show if no tile
+ // Set up and draw tile.
+ extend(tile_data, more_tile_data);
+
+ // HACK: this is FeatureTrack-specific.
+ // If track mode is Auto, determine mode and update.
+ var mode = track.mode;
+ if (mode === "Auto") {
+ mode = track.get_mode(tile_data);
+ track.update_auto_mode(mode);
+ }
+
+ // Draw canvas.
+ var
+ canvas = track.view.canvas_manager.new_canvas(),
+ tile_bounds = track._get_tile_bounds(tile_index, resolution),
+ tile_low = tile_bounds[0],
+ tile_high = tile_bounds[1],
+ width = Math.ceil( (tile_high - tile_low) * w_scale ) + track.left_offset,
+ height = track.get_canvas_height(tile_data, mode, w_scale, width);
+
+ canvas.width = width;
+ canvas.height = height;
+ var tile = track.draw_tile(tile_data, canvas, mode, resolution, tile_index, w_scale, seq_data);
+
+ // Don't cache, show if no tile.
if (tile !== undefined) {
+ track.tile_cache.set(key, tile);
track.show_tile(tile, parent_element, w_scale);
}
- return tile
+ return tile;
}
// Can't draw now, so trigger another redraw when the data is ready
+ var can_draw = $.Deferred();
$.when( tile_data, seq_data ).then( function() {
- view.request_redraw();
+ view.request_redraw(false, false, false, track);
+ can_draw.resolve();
});
- // Indicate to caller that this tile could not be drawn
- return null;
- },
+ // Returned Deferred is resolved when tile can be drawn.
+ return can_draw;
+ },
/**
- * Show track tile and perform associated actions.
+ * Returns canvas height needed to display data; return value is an integer that denotes the
+ * number of pixels required.
+ */
+ get_canvas_height: function(result, mode, w_scale, canvas_width) {
+ return this.height_px;
+ },
+ /**
+ * Draw a track tile.
+ * @param result result from server
+ * @param canvas canvas to draw on
+ * @param mode mode to draw in
+ * @param resolution view resolution
+ * @param tile_index index of tile to be drawn
+ * @param w_scale pixels per base
+ * @param ref_seq reference sequence data
+ */
+ draw_tile: function(result, canvas, mode, resolution, tile_index, w_scale, ref_seq) {
+ console.log("Warning: TiledTrack.draw_tile() not implemented.");
+ },
+ /**
+ * Show track tile and perform associated actions. Showing tile may actually move
+ * an existing tile rather than reshowing it.
*/
show_tile: function(tile, parent_element, w_scale) {
- // Readability.
var
track = this,
- canvas = tile.canvas,
- tile_element = canvas;
+ tile_element = tile.html_elt;
//
- // If tile has message, display message and button to show more data.
- // TODO: need to handle other messages, not assume message === show more data.
+ // Show/move tile element.
//
- if (tile.message) {
- var
- container_div = $(""),
- message_div = $("").addClass("tile-message").text(tile.message).
- // -1 to account for border.
- css({'height': ERROR_PADDING-1, 'width': tile.canvas.width}).appendTo(container_div),
- more_down_icon = $("").addClass("icon more-down").appendTo(message_div),
- more_across_icon = $("").addClass("icon more-across").appendTo(message_div);
- container_div.append(canvas);
- tile_element = container_div;
-
- // Set up actions for icons.
- more_down_icon.click(function() {
- // Mark tile as stale, request more data, and redraw track.
- tile.stale = true;
- track.data_manager.get_more_data(tile.low, tile.high, track.mode, tile.resolution, {}, track.data_manager.DEEP_DATA_REQ);
- track.request_draw();
- }).dblclick(function(e) {
- // Do not propogate as this would normally zoom in.
- e.stopPropagation();
- });
-
- more_across_icon.click(function() {
- // Mark tile as stale, request more data, and redraw track.
- tile.stale = true;
- track.data_manager.get_more_data(tile.low, tile.high, track.mode, tile.resolution, {}, track.data_manager.BROAD_DATA_REQ);
- track.request_draw();
- }).dblclick(function(e) {
- // Do not propogate as this would normally zoom in.
- e.stopPropagation();
- });
- }
- //
- // Show tile element.
- //
+ tile.predisplay_actions();
- // Position tile element, recalculate left position at display time
- var range = this.view.high - this.view.low,
- left = (tile.low - this.view.low) * w_scale;
+ // Position tile element based on current viewport.
+ var left = ( tile.low - (this.is_overview? this.view.max_low : this.view.low) ) * w_scale;
if (this.left_offset) {
left -= this.left_offset;
}
tile_element.css({ position: 'absolute', top: 0, left: left, height: '' });
- parent_element.append(tile_element);
+
+ if ( tile_element.hasClass("remove") ) {
+ // Step (b) for (re)moving tiles. See _draw() function for description of algorithm
+ // for removing tiles.
+ tile_element.removeClass("remove");
+ }
+ else {
+ // Showing new tile.
+ parent_element.append(tile_element);
+ }
// Set track height.
track.max_height = Math.max(track.max_height, tile_element.height());
@@ -2721,15 +3229,48 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
region = (chrom !== undefined && low !== undefined && high !== undefined ?
chrom + ":" + low + "-" + high : "all");
return " - region=[" + region + "], parameters=[" + track.tool.get_param_values().join(", ") + "]";
+ },
+ /**
+ * Set up track to receive tool data.
+ */
+ init_for_tool_data: function() {
+ // Set up track to fetch initial data from raw data URL when the dataset--not the converted datasets--
+ // is ready.
+ this.data_url = raw_data_url;
+ this.data_query_wait = 1000;
+ this.dataset_check_url = dataset_state_url;
+
+ /**
+ * Predraw init sets up postdraw init.
+ */
+ this.predraw_init = function() {
+ // Postdraw init: once data has been fetched, reset data url, wait time and start indexing.
+ var track = this;
+ var post_init = function() {
+ if (track.data_manager.size() === 0) {
+ // Track still drawing initial data, so do nothing.
+ setTimeout(post_init, 300);
+ }
+ else {
+ // Track drawing done: reset dataset check, data URL, wait time and get dataset state to start
+ // indexing.
+ track.data_url = default_data_url;
+ track.data_query_wait = DEFAULT_DATA_QUERY_WAIT;
+ track.dataset_state_url = converted_datasets_state_url;
+ $.getJSON(track.dataset_state_url, {dataset_id : track.dataset_id, hda_ldda: track.hda_ldda}, function(track_data) {});
+ }
+ };
+ post_init();
+ }
}
});
var LabelTrack = function (view, container) {
- this.hidden = true;
- Track.call(this, "label", view, container, {} );
+ Track.call(this, "label", view, container, false, {} );
this.container_div.addClass( "label-track" );
};
extend(LabelTrack.prototype, Track.prototype, {
+ build_header_div: function() {},
init: function() {
// Enable by default because there should always be data when drawing track.
this.enabled = true;
@@ -2755,10 +3296,181 @@ extend(LabelTrack.prototype, Track.prototype, {
}
});
+/**
+ * A tiled track composed of multiple other tracks.
+ */
+var CompositeTrack = function(name, view, container, drawables) {
+ // HACK: modes should be static class vars for most tracks and should update as
+ // needed for CompositeTracks
+ this.display_modes = ["Histogram", "Line", "Filled", "Intensity"];
+ TiledTrack.call(this, name, view, container);
+
+ // Init drawables; each drawable is a copy so that config/preferences
+ // are independent of each other.
+ this.drawables = [];
+ if (drawables) {
+ var
+ ids = [],
+ drawable;
+ for (var i = 0; i < drawables.length; i++) {
+ drawable = drawables[i];
+ ids.push(drawable.dataset_id);
+ this.drawables[i] = drawable.copy();
+ }
+ this.enabled = true;
+ }
+
+ this.update_icons();
+
+ // HACK: needed for saving object for now. Need to generalize get_type() to all Drawables and use
+ // that for object type.
+ this.obj_type = "CompositeTrack";
+};
+
+extend(CompositeTrack.prototype, TiledTrack.prototype, {
+ // HACK: CompositeTrack should inherit from DrawableCollection as well.
+ /**
+ * Returns representation of object in a dictionary for easy saving.
+ * Use from_dict to recreate object.
+ */
+ to_dict: DrawableCollection.prototype.to_dict,
+ add_drawable: DrawableCollection.prototype.add_drawable,
+ /**
+ * Restore object from a dictionary created by to_dict()
+ */
+ // TODO: unify with DrawableCollection.prototype.from_dict?
+ from_dict: function(collection_dict, container) {
+ var collection = new this.constructor( collection_dict.name, view,
+ container, collection_dict.prefs,
+ view.viewport_container, view);
+ var drawable_dict,
+ drawable_type,
+ drawable;
+ for (var i = 0; i < collection_dict.drawables.length; i++) {
+ drawable_dict = collection_dict.drawables[i];
+ drawable_type = drawable_dict['obj_type'];
+ // For backward compatibility:
+ if (!drawable_type) {
+ drawable_type = drawable_dict['track_type'];
+ }
+ // No container for tracks so that it is not made visible.
+ drawable = addable_objects[ drawable_type ].prototype.from_dict( drawable_dict );
+ collection.add_drawable( drawable );
+ }
+ return collection;
+ },
+ change_mode: function(new_mode) {
+ TiledTrack.prototype.change_mode.call(this, new_mode);
+ for (var i = 0; i < this.drawables.length; i++) {
+ this.drawables[i].change_mode(new_mode);
+ }
+ },
+ init: function() {
+ // FIXME: probably should enable based on whether/how many drawaables are enabled.
+ this.enabled = true;
+ this.request_draw();
+ },
+ update_icons: function() {
+ // For now, hide filters and tool.
+ this.action_icons.filters_icon.hide();
+ this.action_icons.tools_icon.hide();
+ },
+ can_draw: Drawable.prototype.can_draw,
+ draw_helper: function(force, width, tile_index, resolution, parent_element, w_scale, more_tile_data) {
+ // FIXME: this function is similar to TiledTrack.draw_helper -- can the two be merged/refactored?
+ var track = this,
+ key = this._gen_tile_cache_key(width, w_scale, tile_index),
+ tile_low = tile_index * DENSITY * resolution,
+ tile_high = tile_low + DENSITY * resolution;
+
+ // Check tile cache, if found show existing tile in correct position
+ var tile = (force ? undefined : track.tile_cache.get(key));
+ if (tile) {
+ track.show_tile(tile, parent_element, w_scale);
+ return tile;
+ }
+
+ // Helper to determine if object is jQuery deferred
+ var is_deferred = function ( d ) {
+ return ( 'isResolved' in d );
+ };
+
+ // Try to get drawables' data.
+ var all_data = [],
+ track,
+ // Flag to track whether we can draw everything now
+ can_draw_now = true,
+ tile_data,
+ seq_data;
+ for (var i = 0; i < this.drawables.length; i++) {
+ track = this.drawables[i];
+ // Get the track data, maybe a deferred.
+ tile_data = track.data_manager.get_data( tile_low, tile_high, track.mode, resolution, track.data_url_extra_params );
+ if ( is_deferred( tile_data ) ) {
+ can_draw_now = false;
+ }
+ all_data.push(tile_data);
+
+ // Get seq data if needed, maybe a deferred.
+ seq_data = null;
+ if ( view.reference_track && w_scale > view.canvas_manager.char_width_px ) {
+ seq_data = view.reference_track.data_manager.get_data(tile_low, tile_high, track.mode, resolution, view.reference_track.data_url_extra_params)
+ if ( is_deferred( seq_data ) ) {
+ can_draw_now = false;
+ }
+ }
+ all_data.push(seq_data);
+ }
+
+ // If we can draw now, do so.
+ if ( can_draw_now ) {
+ // Set up and draw tile.
+ extend(tile_data, more_tile_data);
+
+ var
+ canvas = track.view.canvas_manager.new_canvas(),
+ tile_bounds = track._get_tile_bounds(tile_index, resolution),
+ tile_low = tile_bounds[0],
+ tile_high = tile_bounds[1],
+ width = Math.ceil( (tile_high - tile_low) * w_scale ),
+ height = track.get_canvas_height(tile_data, mode, w_scale, width);
+
+ // FIXME:
+ // (a) right now, only LineTracks respect width/height setting and do not set it in draw_tile;
+ // however, other track types be modified to work this way. This is necessary b/c setting the width/height
+ // clears the canvas and hence prevents non-compliant tracks from being used in CompositeTracks.
+ // (b) need to normalize across tracks before displaying, e.g. set LineTracks' min/max appropriately.
+ canvas.width = width;
+ canvas.height = height;
+ var all_data_index = 0
+ for (var i = 0; i < this.drawables.length; i++, all_data_index += 2) {
+ track = this.drawables[i];
+ tile_data = all_data[ all_data_index ];
+ seq_data = all_data[ all_data_index + 1 ];
+ tile = track.draw_tile(tile_data, canvas, track.mode, resolution, tile_index, w_scale, seq_data);
+ }
+
+ // Don't cache, show if no tile.
+ track.tile_cache.set(key, tile);
+ track.show_tile(tile, parent_element, w_scale);
+ return tile;
+ }
+
+ // Can't draw now, so trigger another redraw when the data is ready
+ var can_draw = $.Deferred(),
+ track = this;
+ $.when.apply($, all_data).then(function() {
+ view.request_redraw(false, false, false, track);
+ can_draw.resolve();
+ });
+
+ // Returned Deferred that is resolved when tile can be drawn.
+ return can_draw;
+ }
+});
+
var ReferenceTrack = function (view) {
- this.hidden = true;
- Track.call(this, "reference", view, { content_div: view.top_labeltrack }, {});
- TiledTrack.call(this);
+ TiledTrack.call(this, "reference", view, { content_div: view.top_labeltrack }, {});
view.reference_track = this;
this.left_offset = 200;
@@ -2769,30 +3481,27 @@ var ReferenceTrack = function (view) {
this.content_div.css("border", "none");
this.data_url = reference_url;
this.data_url_extra_params = {dbkey: view.dbkey};
- this.data_manager = new ReferenceTrackDataManager(CACHED_DATA, this, false);
- this.tile_cache = new Cache(CACHED_TILES_LINE);
+ this.data_manager = new ReferenceTrackDataManager(DATA_CACHE_SIZE, this, false);
};
extend(ReferenceTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
+ build_header_div: function() {},
init: function() {
// Enable by default because there should always be data when drawing track.
this.enabled = true;
},
+ can_draw: Drawable.prototype.can_draw,
/**
* Draw ReferenceTrack tile.
*/
- draw_tile: function(seq, mode, resolution, tile_index, w_scale) {
- var track = this,
- tile_length = DENSITY * resolution;
+ draw_tile: function(seq, canvas, mode, resolution, tile_index, w_scale) {
+ var track = this;
if (w_scale > this.view.canvas_manager.char_width_px) {
- if (seq === null) {
+ if (seq.data === null) {
track.content_div.css("height", "0px");
return;
}
- var canvas = this.view.canvas_manager.new_canvas();
- var ctx = canvas.getContext("2d");
- canvas.width = Math.ceil(tile_length * w_scale + track.left_offset);
- canvas.height = track.height_px;
+ var ctx = canvas.getContext("2d");
ctx.font = ctx.canvas.manager.default_font;
ctx.textAlign = "center";
seq = seq.data;
@@ -2800,27 +3509,25 @@ extend(ReferenceTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
var c_start = Math.round(c * w_scale);
ctx.fillText(seq[c], c_start + track.left_offset, 10);
}
- return new Tile(tile_index, resolution, canvas, seq);
+ return new Tile(track, tile_index, resolution, canvas, seq);
}
this.content_div.css("height", "0px");
}
});
-var LineTrack = function (name, view, container, hda_ldda, dataset_id, prefs) {
+var LineTrack = function (name, view, container, hda_ldda, dataset_id, prefs, filters, tool, data_manager) {
var track = this;
this.display_modes = ["Histogram", "Line", "Filled", "Intensity"];
this.mode = "Histogram";
- Track.call( this, name, view, container, prefs );
- TiledTrack.call( this );
+ TiledTrack.call(this, name, view, container, prefs, filters, tool, data_manager);
this.min_height_px = 16;
this.max_height_px = 400;
- this.height_px = 80;
+ // Default height for new tracks, should be a defined constant?
+ this.height_px = 32;
this.hda_ldda = hda_ldda;
this.dataset_id = dataset_id;
this.original_dataset_id = dataset_id;
- this.data_manager = new DataManager(CACHED_DATA, this);
- this.tile_cache = new Cache(CACHED_TILES_LINE);
this.left_offset = 0;
// Define track configuration
@@ -2828,7 +3535,7 @@ var LineTrack = function (name, view, container, hda_ldda, dataset_id, prefs) {
track: this,
params: [
{ key: 'name', label: 'Name', type: 'text', default_value: name },
- { key: 'color', label: 'Color', type: 'color', default_value: 'black' },
+ { key: 'color', label: 'Color', type: 'color', default_value: get_random_color() },
{ key: 'min_value', label: 'Min Value', type: 'float', default_value: undefined },
{ key: 'max_value', label: 'Max Value', type: 'float', default_value: undefined },
{ key: 'mode', type: 'string', default_value: this.mode, hidden: true },
@@ -2839,8 +3546,8 @@ var LineTrack = function (name, view, container, hda_ldda, dataset_id, prefs) {
track.set_name(track.prefs.name);
track.vertical_range = track.prefs.max_value - track.prefs.min_value;
// Update the y-axis
- $('#linetrack_' + track.track_id + '_minval').text(track.prefs.min_value);
- $('#linetrack_' + track.track_id + '_maxval').text(track.prefs.max_value);
+ $('#linetrack_' + track.dataset_id + '_minval').text(track.prefs.min_value);
+ $('#linetrack_' + track.dataset_id + '_maxval').text(track.prefs.max_value);
track.tile_cache.clear();
track.request_draw();
}
@@ -2863,8 +3570,10 @@ extend(LineTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
var drag_control = $( "
-
-
-
-
+
+
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+${render_metadata( repository, can_reset_metadata=False )}
diff --git a/templates/admin/tool_shed_repository/common.mako b/templates/admin/tool_shed_repository/common.mako
new file mode 100644
index 00000000000..48f69195818
--- /dev/null
+++ b/templates/admin/tool_shed_repository/common.mako
@@ -0,0 +1,168 @@
+<%def name="render_metadata( repository, can_reset_metadata=False )">
+
+
+
+
+ Tools - click the name to view tool related information
+
+
+
+
+ %for tool_dict in tool_dicts:
+ name
+ description
+ version
+ requirements
+
+
+ %endfor
+
+
+ ${tool_dict[ 'name' ]}
+
+
+ ${tool_dict[ 'description' ]}
+ ${tool_dict[ 'version' ]}
+
+ <%
+ if 'requirements' in tool_dict:
+ requirements = tool_dict[ 'requirements' ]
+ else:
+ requirements = None
+ %>
+ %if requirements:
+ <%
+ requirements_str = ''
+ for requirement_dict in tool_dict[ 'requirements' ]:
+ requirements_str += '%s (%s), ' % ( requirement_dict[ 'name' ], requirement_dict[ 'type' ] )
+ requirements_str = requirements_str.rstrip( ', ' )
+ %>
+ ${requirements_str}
+ %else:
+ none
+ %endif
+
+
+
+
+
+ Workflows - click the name to import
+
+
+
+
+ <% index = 0 %>
+ %for workflow_tup in workflow_tups:
+ <%
+ import os.path
+ relative_path = workflow_tup[ 0 ]
+ full_path = os.path.abspath( relative_path )
+ workflow_dict = workflow_tup[ 1 ]
+ workflow_name = workflow_dict[ 'name' ]
+ if 'steps' in workflow_dict:
+ ## Initially steps were not stored in the metadata record.
+ steps = workflow_dict[ 'steps' ]
+ else:
+ steps = []
+ format_version = workflow_dict[ 'format-version' ]
+ annotation = workflow_dict[ 'annotation' ]
+ %>
+ name
+ steps
+ format-version
+ annotation
+
+
+ <% index += 1 %>
+ %endfor
+
+
+
+
+ %if steps:
+ ${len( steps )}
+ %else:
+ unknown
+ %endif
+
+ ${format_version}
+ ${annotation}
+
+
+
+
+ Data types
+
+
+
+
+ %for datatypes_dict in datatypes_dicts:
+ <%
+ extension = datatypes_dict.get( 'extension', ' ' )
+ dtype = datatypes_dict.get( 'dtype', ' ' )
+ mimetype = datatypes_dict.get( 'mimetype', ' ' )
+ subclass = datatypes_dict.get( 'subclass', ' ' )
+ %>
+ extension
+ type
+ mimetype
+ subclass
+
+
+ %endfor
+ ${extension}
+ ${dtype}
+ ${mimetype}
+ ${subclass}
+
+
+
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+
+
+
+
+
+
+
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+%if metadata:
+
+ ${tool.command}
+
+
+
+
+
+ %for test_dict in tests:
+ <%
+ inputs = test_dict[ 'inputs' ]
+ outputs = test_dict[ 'outputs' ]
+ required_files = test_dict[ 'required_files' ]
+ %>
+ name
+ inputs
+ outputs
+ required files
+
+
+ %endfor
+ ${test_dict[ 'name' ]}
+
+ %for input in inputs:
+ ${input[0]}: ${input[1]}
+
+ %endfor
+
+ %for output in outputs:
+ ${output[0]}: ${output[1]}
+
+ %endfor
+
+ %for required_file in required_files:
+ ${required_file[0]}
+
+ %endfor
+ ${job.traceback}
+ ${job.traceback | h}
%endif
%if job.stderr or job.info:
Tool execution generated the following error message:
%if job.stderr:
- ${job.stderr}
+ ${job.stderr | h}
%elif job.info:
- ${job.info}
+ ${job.info | h}
%endif
%else:
Tool execution did not generate any error messages.
%endif
%if job.stdout:
The tool produced the following additional output:
- ${job.stdout}
+ ${job.stdout | h}
%endif
%else:
The tool did not create any additional job / error info.
diff --git a/templates/display_common.mako b/templates/display_common.mako
index 937fec95b85..c8aef4f7271 100644
--- a/templates/display_common.mako
+++ b/templates/display_common.mako
@@ -138,7 +138,7 @@
%if history.slug and history.user.username:
<% return h.url_for( controller='/history', action='display_by_username_and_slug', username=history.user.username, slug=history.slug, qualified=qualify ) %>
%else:
- <% return h.url_for( controller='/history', action='view', id=trans.security.encode_id( history.id ), qualified=qualify ) %>
+ <% return h.url_for( controller='/history', action='view', id=trans.security.encode_id( history.id ), qualified=qualify, use_panels=context.get('use_panels', True) ) %>
%endif
%def>
diff --git a/templates/embed_base.mako b/templates/embed_base.mako
index b55ebb13b93..f5af1de33b3 100644
--- a/templates/embed_base.mako
+++ b/templates/embed_base.mako
@@ -44,7 +44,7 @@
- %if len( grid.global_actions ) < 4:
+ %if len( grid.global_actions ) < 3:
%for action in grid.global_actions:
+
+
+
+
+
+
+