PDA

View Full Version : [FIXED-152][3.x/2.x] Ext sometimes adds hashmarks to my URLs



mschwartz
13 Apr 2009, 7:29 AM
Ext should leave my URLs alone. I want to use #whatever for my own purposes.

<a href="#" whatever>

in the code should be

<a href="javascript: void(0);"

everywhere

stever
14 Apr 2009, 7:01 PM
I agree. Though most of time the reason is that there was a JS or other error. If everything is working fine, I don't see it change the url like that. Therefore, I see it a lot in testing! Hopefully never on a live site...

brian.moeskau
14 Apr 2009, 9:28 PM
That is default browser behavior since "#" is a perfectly valid anchor to navigate to. You can prevent that from showing up in the url by using the stopEvent option in any event handlers for the anchor tag.

Condor
14 Apr 2009, 10:24 PM
That is default browser behavior since "#" is a perfectly valid anchor to navigate to. You can prevent that from showing up in the url by using the stopEvent option in any event handlers for the anchor tag.

I completely agree, but the point was that certain Ext components use anchors with href="#" that do not call stopEvent.

Unfortunately mschwartz didn't specify which components...

brian.moeskau
14 Apr 2009, 10:32 PM
Yeah, I wasn't sure if he was referring to a specific component. If so, it should probably be posted as a bug for the component to prevent internally. I'm not sure what component would do that off the top of my head.

mschwartz
15 Apr 2009, 4:57 AM
Slider.js:



cn:{cls:'x-slider-end',cn:{cls:'x-slider-inner',cn:[{cls:'x-slider-thumb'},{tag:'a', cls:'x-slider-focus', href:"#", tabIndex: '-1', hidefocus:'on'}]}}
DatePicker.js:


'<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',

m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
TabPanel.js:


'<a class="x-tab-right" href="#" onclick="return false;"><em class="x-tab-left">',
etc. ( you can do your own grep :) )

Apparently I wasn't perfectly clear about the issue. Let me give an example.

I make an application that's a Viewport with a TabPanel with three tabs: 'Tab A', 'Tab B', 'Tab C'

When someone activates 'Tab A' I want to be able to do something like:


window.location.href += '#tab-a';
Similarly for 'Tab B' and 'Tab C'.

Now people can copy / paste the URL (http://mysite.com/myapp#tab-c) into a message board post or IM or email message or whatever, and when the recipient clicks on the link or pastes it into his browser, I can detect the #tab-c at the end and automatically activate 'Tab C' in my Ext.onReady function.

I can think of other uses for the # on the end of URLs, too, like other kinds of state information.

It's also an issue during development. If there's a # at the end of the URL, you can't just activate the address bar and hit return to reload a page (browsers do different things when you do this vs. hitting F5 or whatever).

Condor
15 Apr 2009, 5:16 AM
I completely understand why you wouldn't want the url hash to change.

I also did the grep on the source, but if you try any of those components you'll notice that the click event isn't propagated, so the url hash is never changed.

What exactly did you do to change the url hash to #?

mschwartz
15 Apr 2009, 5:20 AM
What I'm seeing is http://myurl.com#

And I'm not putting the # on the end by typing it in the address bar or through code.

mschwartz
15 Apr 2009, 5:22 AM
I'll also add this to the discussion.

If you use window.open() with parameters to disable the address bar, the newer browsers (FF 3 at least) actually show the address bar but don't let you edit the URL. You can click on the address bar and hit return and it will reload the page, but not with the # on the end.

Why? It sees #(anything) and tries to find the anchor <a name=anything in the already loaded page and will scroll to that if found.

evant
15 Apr 2009, 5:33 AM
As Condor said, specifically, which components are causing this to happen? The components that use anchors are stopping their events, so it shouldn't be an issue.

mschwartz
15 Apr 2009, 5:37 AM
I don't know which components, since I use most of them in my application (trees, date pickers, slider, tabs, grids, etc). I see the # at the end of my URLs all day long.

What I do know is that changing the '#' to 'javascript: void(null)' won't break anything and it will fix the problem and make developers' jobs a lot easier.

mschwartz
12 May 2009, 7:16 AM
I'm bumping this with new information.

I have a menu on a button on a toolbar, one of the items' handler functions opens a new browser window:



if (!new_window || new_window.closed) {
new_window = window.open('/url.../', 'newwindow', 'toolbar=no,directories=no,status=no,menubar=no');
}
new_window.focus();


Picking that menu item, it opens a new browser window and adds a # to the end of the URL in the first browser.

Please consider doing a search/replace of href=# with href=javascript:void(null) everywhere ...

Condor
12 May 2009, 7:20 AM
1. Can you post the full config object for the menu item?
2. Is this in Ext 2.2.1?

mschwartz
12 May 2009, 7:43 AM
And I can't reproduce it with a simple test case.

As I step through the code, there's a lot of defered routines getting called and the timers for those get messed up enough while stepping that the information I am seeing isn't very meaningful.

Though I can see the # get added after stepping out of the click handlers in BaseItem. That is, I can't step anymore, firebug shows me the HTML. Some defered or timer based event is adding the #. And the menu doesn't hide...

If I run it without breakpoints and stepping into every routine, the # appears and the menu does hide.

mschwartz
12 May 2009, 7:47 AM
Ext 3.1-rc1

The toolbar is dynamically generated.



var items = []; // toolbar items
var tools = []; // tools menu

tools.push({
text: 'Notepad',
cls: 'x-btn-text-icon',
icon: '/images/icons/notepad_icon.gif',
handler: function() {
if (!notepad_window || notepad_window.closed) {
notepad_window = window.open('/cms/extui/Notepad/', 'notepadwindow', 'toolbar=no,directories=no,status=no,menubar=no');
}
notepad_window.focus();
}
});
items.push({
text: 'Tools',
cls: 'x-btn-text-icon',
icon: '/cms/images/cntrlproperties_16.gif',
menu: tools
});

return new Ext.Toolbar({
items: items
});

Condor
12 May 2009, 7:51 AM
Could you try if delaying the focus helps?

notepad_window.focus.defer(10);

mschwartz
12 May 2009, 7:53 AM
I definitely think it's timing related.

The popup window does take a while to render, because it's loading Ext as well. The menu on the first browser window stays up for a few seconds before getting hidden.

I'm going to see what happens if the url is about:blank

mschwartz
12 May 2009, 7:53 AM
Could you try if delaying the focus helps?

notepad_window.focus.defer(10);

trying this first

mschwartz
12 May 2009, 7:55 AM
defer(10) didn't fix it

trying this:



(function() {
if (!notepad_window || notepad_window.closed) {
notepad_window = window.open('/cms/extui/Notepad/', 'notepadwindow', 'toolbar=no,directories=no,status=no,menubar=no');
}
notepad_window.focus();
}).defer(10);

mschwartz
12 May 2009, 7:57 AM
^^^ nope

I'll defer(1000) and see

mschwartz
12 May 2009, 8:00 AM
Nope

Condor
12 May 2009, 8:01 AM
Ignore this...

I also have my doubts on BaseItem registering 2 click events.

Could you try this:

Ext.override(Ext.menu.BaseItem, {
setHandler : function(handler, scope){
this.handler = handler;
this.scope = scope;
return this;
},
onClick : function(e){
Ext.callback(this.handler, this.scope || this, [e]);
if(!this.disabled && this.fireEvent("click", this, e) !== false
&& (this.parentMenu && this.parentMenu.fireEvent("itemclick", this, e) !== false)){
this.handleClick(e);
}else{
e.stopEvent();
}
}
});

(oh no, I would need to fix the contructor too)

mschwartz
12 May 2009, 8:02 AM
heh heh heh

I don't know what the bug is, but I do know this.

When I mouse over the menu item, it shows the URL in the browser status bar, with the # on the end. Exactly the bad URL I see after clicking on the menu item.

mschwartz
12 May 2009, 8:03 AM
Trying the override...

mschwartz
12 May 2009, 8:04 AM
Override didn't fix it.

mschwartz
12 May 2009, 8:07 AM
My bad, the override did fix it. I needed to clear my browser cache.

Awesome, dude!

mschwartz
12 May 2009, 8:51 AM
awwww... not so awesome

With the above override, Ext.Window.close() doesn't work properly for some of my dialogs. That is, they don't close when close() is called.

Condor
12 May 2009, 11:35 PM
The previous patch was complete nonsense. The only reason it worked was that it rearranges the call order in the click event.

Am I correct in expecting that this problem only arises on Internet Explorer?

In that case it could be caused by the fact that IE only has a single event object and the clicked event is stopped AFTER the handler is called. When the handler generates another event it replaces the click event and the click event is never stopped.

Try if this override fixes the problem:

Ext.override(Ext.menu.Item, {
onClick : function(e){
if(!this.href){
e.stopEvent();
}
Ext.menu.Item.superclass.onClick.apply(this, arguments);
},
handleClick : Ext.menu.Item.superclass.handleClick
});

mschwartz
13 May 2009, 4:37 AM
I'm using Firefox actually.

Will try the override.

(missing a , before handleClick)

mschwartz
13 May 2009, 4:40 AM
This override seems to work.

Any reason not to hide the menu right here as well?

I suggest this because the menu stays up for a while in this case, and in the case where you're using something like miframe.

Condor
13 May 2009, 5:59 AM
The current implementation lets you stop hiding the menu by returning false from the menu item 'click' or menu 'itemclick' event.

That feature would be lost if you move the menu hide from handleClick to onClick.

If your click event handler is very time consuming you should consider delaying or buffering it, e.g.

{
text: 'My menuitem',
listeners: {
click: function(){
// something very slow
},
delay: 1
}
}

mschwartz
7 Jul 2009, 7:18 AM
Now that 3.0.0 is out, I want to bump this.

Please consider replacing all the href="#" in the code with href="javascript:void(null)" so there's no way to mess up our URLs.

It adds a few bytes to the code in a handful of places, but it is well worth it.

In my case, I have Ext running in a window opened with window.open() and the address bar disabled so the user can't edit that to remove the #.

The Ext menu code seems to add # to my URLs a lot during development.

erki
5 Aug 2009, 3:00 AM
Hello.

I'm also seeing this bug in Ext 2.3.0. I have Ext menu and clicking on the menuitem opens a popup.
There seems to be a some kind of race condition, because sometimes Ext will add "#" at the end of the URL after the click and sometimes it doesn't. In my case it's especially bad, because I'm using "<base href=..." and it will not only add a "#" but it also redirects to a different location.

The following code fixes this problem:


Ext.override (Ext.menu.Item, {
onRender : function(container, position){
var el = document.createElement("a");
el.hideFocus = true;
el.unselectable = "on";
el.href = this.href || "#";
el.onclick = function () { return false; };
if(this.hrefTarget){
el.target = this.hrefTarget;
}
el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
el.innerHTML = String.format(
'<img src="{0}" class="x-menu-item-icon {2}" />{1}',
this.icon || Ext.BLANK_IMAGE_URL, this.itemText||this.text, this.iconCls || '');
this.el = el;
Ext.menu.Item.superclass.onRender.call(this, container, position);
}
});


Replacing all the href="#"-s would also be a solution, but I'm not sure if this would only be hiding the problem or really fixing it...

Tested on Firefox 3.x

erki
5 Aug 2009, 4:24 AM
Here's a testcase:


var menu = new Ext.menu.Menu ({
items: [
{
text: "Click me",
handler: _openPopup
}
]
});

var i = (new Date).getTime();

function _openPopup (comp, ev)
{
window.open ("http://www.google.com/", "test" + i++, "width=100,height=100");
}

function _showMenu (b, ev)
{
menu.showAt (ev.getXY());
}

Ext.onReady(function() {

var win = new Ext.Window ({
width: 620,
height: 300,
plain: true,
items: [
{
xtype: "button",
text: "Test Me",
handler: _showMenu
}
]
});

win.show (this);

});

mschwartz
5 Aug 2009, 4:36 AM
Ext.override (Ext.menu.Item, {
onRender : function(container, position){
var el = document.createElement("a");
el.hideFocus = true;
el.unselectable = "on";
el.href = this.href || "javascript: void(null);";
el.onclick = function () { return false; };
if(this.hrefTarget){
el.target = this.hrefTarget;
}
el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
el.innerHTML = String.format(
'<img src="{0}" class="x-menu-item-icon {2}" />{1}',
this.icon || Ext.BLANK_IMAGE_URL, this.itemText||this.text, this.iconCls || '');
this.el = el;
Ext.menu.Item.superclass.onRender.call(this, container, position);
}
});


My proposed fix in red.
Everywhere in the source there's '#'

It could be done as:
Ext.nsFN = 'javascript: void(null)';
to save a few bytes everywhere

Condor
5 Aug 2009, 4:55 AM
I'm not entirely against this patch, but it doesn't solve the root of the problem:

The dom click event isn't stopped before the menuitem click event handler is called.

ps. This bug is still valid for Ext 3.0.0.

mystix
5 Aug 2009, 5:13 AM
[ moved to 3.x bugs from 2.x bugs ]

evant
5 Aug 2009, 9:18 PM
There is a call to stopEvent if there is no href defined.

I tried the test case a few posts up a number of times on IE and FF and was never able to reproduce it.

Condor
5 Aug 2009, 9:42 PM
There is a call to stopEvent if there is no href defined.

Yes, but it's executed after the 'click' and 'itemclick' events are fired from Ext.menu.BaseMenu.onClick.


I tried the test case a few posts up a number of times on IE and FF and was never able to reproduce it.

Really? It only took 3 tries on my FF3.5/WinXP.

erki
6 Aug 2009, 1:21 AM
FWIW, opening the popup seems to be the root of the problem. If I call stopEvent() before opening popup, everything works.

For example, this change to my testcase fixes the problem:


function _openPopup (comp, ev)
{
ev.stopEvent();
window.open ("http://www.google.com/", "test" + i++, "width=100,height=100");
}


This change however does not:


function _openPopup (comp, ev)
{
window.open ("http://www.google.com/", "test" + i++, "width=100,height=100");
ev.stopEvent();
}

mjlecomte
15 Aug 2009, 3:13 PM
This thread has remained in INFOREQ status for some time now and I don't see any test case posted as requested per http://extjs.com/forum/showthread.php?p=341947#post341947.

I'm going to update the status to CLOSED in absence of a test case. Please post a test case to have the issue reopened.

Condor
17 Aug 2009, 12:03 AM
The testcase posted by erki is able to reproduce the bug for me, so I think this thread deserves an [OPEN] status.

mjlecomte
17 Aug 2009, 7:27 PM
I can't reproduce the problem using today's svn build with this test case:


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all.js"></script>
<script type="text/javascript">
var menu = new Ext.menu.Menu({
items: [{
text: "Click me",
handler: _openPopup
}]
});

var i = (new Date).getTime();

function _openPopup(comp, ev){
window.open("http://www.google.com/", "test" + i++, "width=100,height=100");
}

function _showMenu(b, ev){
menu.showAt(ev.getXY());
}

Ext.onReady(function(){

var win = new Ext.Window({
width: 620,
height: 300,
plain: true,
items: [{
xtype: "button",
text: "Test Me",
handler: _showMenu
}]
});

win.show(this);

});
</script>
</head>
<body>
</body>
</html>

Condor
17 Aug 2009, 10:48 PM
It can easily reproduce the problem using the above example (it takes me about 5 tries on avarage).

Using:
- Windows XP SP3 running on a P4 530/2GB
- Firefox 3.5.2 (with Firebug 1.4.2)
- Ext trunk SVN rev. 5110

Are you sure you don't see the hash mark appended to the url (or do you have a lightning-fast computer)?

mjlecomte
18 Aug 2009, 2:42 AM
Ah, ok. I misunderstood I guess. I thought the problem was the hash was added to the new window that was opened. I see it on the originating page within 6 tries.

Condor
18 Aug 2009, 3:26 AM
This other issue (http://extjs.com/forum/showthread.php?t=77380) indeed seems to be the same as this bugreport.

That report also mentions that href="#" anchors are ugly in Chrome because it shows the statusbar on hover.

Jamie Avins
10 Nov 2009, 1:32 PM
Resolved in svn 5606 for the 3.1 release. If an href is not defined, the default anchor event is prevented.