Opened 7 years ago

Closed 7 years ago

Last modified 5 years ago

#8851 closed bug (duplicate)

Tabs widget fails on inline tabs if invoking URL contains a query string

Reported by: savvyaviator Owned by: savvyaviator
Priority: minor Milestone: 1.10.0
Component: ui.tabs Version: 1.9.2
Keywords: Cc:
Blocked by: Blocking:

Description

Serious bug introduced starting in jQuery UI 1.9.0 that causes the tabs widget to fail on inline tabs if the invoking URL contains a query string ("?xxx"). This is a crippling problem for content management systems like Joomla! where many URLs contain query strings. The problem did not exist with jQuery UI 1.8.

The problem is the function isLocal( anchor ) which attempts to test whether the anchor is local (inline tab) or non-local (remote ajax tab). If the invoking URL (window.location) contains a query string, isLocal always returns false even if the tested anchor is actually local (e.g., "#panel-1").

The buggy code is:

var rhash = /#.*$/;
function isLocal( anchor ) {
	return anchor.hash.length > 1 &&
	anchor.href.replace( rhash, "" ) === location.href.replace( rhash, "" );
}

One way to fix it might be:

var rhash = /#.*$/;
var rquery = /\?[^#]*/;
function isLocal( anchor ) {
	return anchor.hash.length > 1 &&
	anchor.href.replace( rhash, "" ) === 
		location.href.replace( rquery, "" ).replace( rhash, "" );
}

Another possibility (that I think is more elegant) is:

function isLocal( anchor ) {
	return anchor.hash.length > 1 &&
	anchor.host === location.host &&
	anchor.pathname === location.pathname;
}

Change History (11)

comment:1 Changed 7 years ago by tj.vantoll

Owner: set to savvyaviator
Status: newpending

@savvyaviator Thanks for taking the time to contribute to the jQuery UI project! There have been changes to that function since 1.9 originally came out, specifically - https://github.com/jquery/jquery-ui/commit/c6b52db892703ba14153800dbf620db509acb9e6#ui/jquery.ui.tabs.js.

Can you check whether this is still an issue with jQuery in master? You can use http://code.jquery.com/ui/jquery-ui-git.css and http://code.jquery.com/ui/jquery-ui-git.js to test with.

Thanks.

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

This is working correctly. If you have two URLs with the same path, but different query strings, then they point to two different resources. Can you please provide an example of what you think is behaving incorrectly?

comment:3 in reply to:  2 Changed 7 years ago by savvyaviator

Status: pendingnew

Replying to scott.gonzalez:

This is working correctly. If you have two URLs with the same path, but different query strings, then they point to two different resources. Can you please provide an example of what you think is behaving incorrectly?

It is NOT working correctly in the latest distribution release 1.9.2.

If the URL that invokes the page containing the tabs widget has ANY query string (even a zero-length one, just a terminating "?") and the tabs are inline (i.e., <li><a href="#xxxx">Tab Label</a></li>), then the isLocal(anchor) function returns false instead of true and the tabs widget tries to treat the anchor as a non-local pane and performs an ajax load.

I have verified this failure with both Chrome and Firefox using jQuery UI 1.9.0, 1.9.1 and 1.9.2. I have also verified that both of the code revisions to the isLocal() function that I outlined above resolve it.

I have not yet tried the version from github, but will do so and report back.

The problem is apparently caused by the fact that when the browser tries to absolutize a relative URL like "#xxxx" it prepends the invoking host and path but NOT any invoking query string. In other words, if the invoking URL is:

https://www.foo.com/yabba/dabba/doo?alpha=bravo

then the relative URL "#xxxx" is resolved to

https://www.foo.com/yabba/dabba/doo#xxxx

and the current isLocal() code (which trims the #xxxx but not the ?alpha=bravo) gets an unequal compare and concludes incorrectly that #xxxx is non-local.

--Mike Busch

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

Status: newpending

I'm not seeing this behavior. For example, if I go to http://view.jqueryui.com/master/demos/tabs/default.html?query=test the tabs work properly. I need to see a reduced page that shows the problem.

comment:5 in reply to:  4 Changed 7 years ago by savvyaviator

Status: pendingnew

Replying to scott.gonzalez:

I'm not seeing this behavior. For example, if I go to http://view.jqueryui.com/master/demos/tabs/default.html?query=test the tabs work properly. I need to see a reduced page that shows the problem.

I'm getting the same result as you are on that page, so I will need to investigate further and report back.

The problems I am seeing occur on a Joomla!-based website. I will try to generate a non-Joomla!-based test case that illustrates the problem if I can.

comment:6 in reply to:  4 ; Changed 7 years ago by savvyaviator

Replying to scott.gonzalez:

I'm not seeing this behavior. For example, if I go to http://view.jqueryui.com/master/demos/tabs/default.html?query=test the tabs work properly. I need to see a reduced page that shows the problem.

Okay, Scott, I have it isolated now into three minimal test cases that clearly demonstrate the issue.

https://www.savvyanalysis.com/test/test1.html?query=test works fine. This is identical to the tabs widget demo you cited, except that I moved it to my server and linked to jQuery 1.8.3 and jQueryUI 1.9.1 from the Google CDN.

https://www.savvyanalysis.com/test/test2.html?query=test demonstrates the failure. It is identical to the first case with one exception: the head section of the HTML page contains one additional HTML element:

<base href="https://www.savvyanalysis.com/test/test2.html">

You'll notice that this page works fine so long as you leave off the query string in the invoking URL, but it fails if you include the query string.

Please note that Joomla! (the world's most widely used content management system on the web) generates this <BASE...> element on every page, and its href attribute properly includes the host and path of the invoking URL, but EXCLUDES any ?querystring or #fragmentid that may be included in the invoking URL. That's why this bug is urgent in my opinion. I do not know whether other popular CMS such as Drupal or Wordpress generate such <BASE...> elements on their pages, but that's certainly possible.

https://www.savvyanalysis.com/test/test3.html?query=test shows a work-around that I have come up with until this bug in the jQueryUI tabs widget is fixed. It is identical to the second case, but with a Javascript hack included prior to invoking the $('#tabs').tabs() statement that looks for a <BASE> element in the DOM and (if there is one) resets its href to agree with the invoking URL (including any ?querystring or #fragmentid). The workaround reads as follows:

<head>
...
<script>
$(function() {
    var baseElements = document.getElementsByTagName("base");
    if( baseElements.length>0 ) {
        baseElements[0].href = document.location.href;
    }
    $( "#tabs" ).tabs();
});
</script>
</head>

Yuck!

In my opinion, this really needs to be fixed in jQueryUI 1.9.x. It was not a problem in jQueryUI 1.8.24 and earlier. I will temporarily incorporate the ugly workaround hack in my Joomla!-generated web pages to circumvent the issue until it is (hopefully) corrected in the jQueryUI library.

Thanks in advance. --Mike

Last edited 7 years ago by savvyaviator (previous) (diff)

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

Resolution: duplicate
Status: newclosed

Duplicate of #7822.
Here we go again...

This is not a bug. This is correct behavior, because <base> is changing your #tabs-1 into https://www.savvyanalysis.com/test/test2.html#tabs-1 and not https://www.savvyanalysis.com/test/test2.html?query=test#tabs-1. Therefore, the link is no longer pointing to the same page.

comment:8 Changed 7 years ago by mikesherov

I'm just going to leave this here: https://github.com/joomla/joomla-cms/pull/189

comment:9 Changed 7 years ago by philw

My version... if we have a URL with a query parameter which has a space in it, then jQueryUi 1.9.2 returns false for isLocal() for IE(6,7,8,9, and 10). For Chrome or Firefox it returns the correct value, which is true. If I change all the URL spaces for something else, jQueryUI gets it right for all browsers.

The work around for those of us with no "remote" tabs is to replace the isLocal function with something which simply returns true.

It may not be a defect to you, but it was to me, so I posted this here as it may help others when they have this problem.

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

@philw The space has nothing to do with this ticket. See #8896.

comment:11 in reply to:  6 Changed 5 years ago by ricardovigatti

<script> $(function() {

var baseElements = document.getElementsByTagName("base"); if( baseElements.length>0 ) {

baseElements[0].href = document.location.href;

} $( "#tabs" ).tabs();

}); </script>

This fix worked very well for me. Thank U. Also, I do not think this is a jQuery UI bug, but a bug in Joomla!

Note: See TracTickets for help on using tickets.