Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#10664 closed feature (wontfix)

Add possibility to make tab contents not visible rather set display to none

Reported by: dma_k Owned by:
Priority: minor Milestone: none
Component: ui.tabs Version: 1.10.3
Keywords: Cc:
Blocked by: Blocking:

Description

In case tab contents is very heavy (tab controls switching panels of the application), tab switching becomes quite slow on Firefox and IE. I think this happens because once element is hidden, FF fires resize event (with zero size) and once element is shown, FF fires another resize event (with actual size), resulting two events needed to be processed (for hiding tab and for showing tab) on each tab switch. If tab contents logic tries to adjust its contents based on e.g. width (for example DataTables), it takes some time to switch tabs.

Solution: Implement alternative strategy that will apply "visible:hidden" CSS style to tab panel rather than "display:none" (or delegate this functionality to customizable callback or function that could be overridden). This strategy will only work if tab panels are absolutely positioned.

Chrome is not affected: it is smart not to send these events and switching happens very quickly.

Change History (4)

comment:1 Changed 7 years ago by Scott González

Resolution: wontfix
Status: newclosed

Sounds like DataTables should handle this situation better.

comment:2 Changed 7 years ago by dma_k

DataTables is just an example. There are other in-house components that listen on window resize and do some recalculation. Maybe you've go an idea how this could be handled better? Let's assume that event handler gets two events: one that new box dimensions are 275×0 (when it is hidden) and another is 288×804 (once it is shown back). Filtering out these events is not trivial.

comment:3 Changed 7 years ago by Scott González

.is( ":visible" ) seems very trivial to me. Is there a reason that's not sufficient? Any complex layout changes during a resize or scroll already need a fair amount of logic to not destroy the frame rate, so I would say developers should already be aware of these issues.

comment:4 Changed 7 years ago by dma_k

.is(":visible") will filter the 1st event – that's true. But 2nd event triggered when panel is shown, does not differ from "normal" resize event and is fired when panel is visible. I can see how element positions are recalculated and they are shifted / adjusted when panel is shown, so it is the most performance.

I considered the following solutions:

  • Suppress the 2nd event, if the previous event for fired for hidden panel (e.g. height=0). This is not very clean solution, as there are several events in a row fired when panel is shown.
  • Listen on beforeActivate() and set some flag (say, uiTabIsSwitching) which is reset in activate(); if the flag is raised, then ignore resize events. A bit cumbersome solution, as some deep component should have a reference to tab control (or some global) to access this flag.
  • Finally, try to intercept the hiding of the element. By examining the code of tab UI, I found out that it is already possible. Here is the sketch that worked for me:
$.widget("ui.tabs", $.ui.tabs, {
	options: {
		visibilityHide: false
	},

	_create: function() {
		this._super();

		if (this.options.visibilityHide) {
			this.options.hide = true;
			this.options.show = true;
		}
	},
	
	_hide: function(element, options, callback) {
		if (!this.options.visibilityHide) {
			this._super(element, options, callback);
			return;
		}
		
		element.css({ "visibility" : "hidden" });
		callback();
	},

	_show: function(element, options, callback) {
		if (!this.options.visibilityHide) {
			this._super(element, options, callback);
			return;
		}
		
		element.css({ "visibility" : "", "display" : "" });
		callback();
	}
});
Note: See TracTickets for help on using tickets.