PDA

View Full Version : Unpredictable behavior of Ext.History and back button on IE



grzegorz.borkowski
26 Sep 2009, 7:20 AM
Last 3 days I'm trying to fix the problem of Ext.History behavior on IE, but with no result. The case is following.
We use Ext.History in the application to allow users for navigation across screens with browser buttons. The application is quite big and complicated, but history code is rather simple and is based on the code from Ext samples. We have a container that caches some panels, and the visible panel is swapped during history navigation. This works properly when you follow the links in the application: panels are swapped, the hash in URLs changes, the hidden iframe gets updated (I changed its style to make its content visible for debugging). When you press back button once, it reverts to previous state. But then if you try to press it second time, or try to press forward button, it doesn't work. The forward button is not enabled, which is strange (you just moved one step back, so you should be able to go one step forward from here - but you can't). Pressing back also doesn't work correctly: sometimes url gets refreshed, but hidden iframe content doesn't, and application is not updated. Generally application works completely unpredicable: your url hashes are no longer synchronized with application state, nor with iframe state.
After lots of debugging, it seems to me that the IE bahavior is following: when you press back button, it moves back the iframe content to previous state. Ext timer discovers this change, so it calls the onchange listeners and updates the URL hash to synchronize it with new state. It seems that sometimes Internet Explorer spots this URL hash change and treats it as user navigation to the new history state (forward). Because of this, it disables the forward button (because it thinks you just clicked some link and moved forward with history, so you can't move forward anymore).
During debugging, after pressing the back button I see both buttons (back and forward) enabled for a while, but then after updating the url hash by Ext.History code, the forward button gets disabled, and history gets broken.
It's the same in IE6, IE7 and IE8 (in quirks mode).
The strange thing is that Ext sample works correctly. My code is similar, and it doesn't work. The only difference is the amount of work which happens in history change listeners, and the size of application. What's more, it seems to me that if I simplify the handler code (e.g. just show some empty panel) it mostly (means usually, 90% of time) works. When I add more ogic, and the panels are complicated, it breaks (almost always).
Has anybody observed similar behavior? What's the explanation of this behavior?

aconran
27 Sep 2009, 10:14 AM
I haven't seen this type of behavior. :-/

Do you think you would be able to isolate this enough that you could create a testcase that we could troubleshoot?

grzegorz.borkowski
27 Sep 2009, 12:30 PM
I'll try, though it can be not that easy. I'll see what I can do.

grzegorz.borkowski
28 Sep 2009, 4:05 AM
Here is a test case, based on our code. I was able to reproduce the problem both on IE 7 and IE 8. Click all the links on the page one by one, and then press back button. The forward button usually doesn't work then.


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title id='title'>Title</title>

<!-- ** CSS ** -->
<!-- base library -->
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />

<!-- overrides to base library -->


<!-- ** Javascript ** -->
<!-- base library -->
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all-debug.js"></script>


<!-- overrides to base library -->

<!-- extensions -->

<!-- page specific -->

<script type="text/javascript">
Ext.BLANK_IMAGE_URL = '../../resources/images/default/s.gif';

Ext.namespace('FN.COMMON');

FN.COMMON.Templates = {
menuListTpl: new Ext.XTemplate(
'<ul id="baseTasks" >',
'<tpl for=".">',
'<li><img src="' + Ext.BLANK_IMAGE_URL + '" class="{cls}"/><a href="#{href}" class="navigation-link"><span id="{id}">{label}</span></a></li>',
'</tpl>', '</ul>')
};




FN.COMMON.Util = {
tokenDelimiter : ':' // Should be something that won't be in component ids.
}





//"buffered container"
FN.COMMON.ContentContainer = Ext.extend(Ext.Container, {
autoEl : 'div',
layout : 'card',
defaults : {
frame : true
},
/**
* How many panels should be cached
*/
bufferSize : 4,
swapToDefaultPanel : function() {
this.swapPanel('A');
},
initComponent : function() {
// private, instance-scoped variable: the queue which keeps the most recently used components
var mruQueue = [];
this.swapPanel = function(id) {
//local reference which can be inspected with firebug
//(I wasn't able to inspect directly mruQueue in firebug)
var queue = mruQueue;
var layout = this.getLayout();
var component;
if (this.items) {
component = this.getComponent(id);
}
if (component) {
layout.setActiveItem(id);
if (queue[0] !== id) {
queue.remove(id);
queue.unshift(id);
}
} else {
component = Ext.ComponentMgr.create({xtype: "panel", id: id, title: id});
this.add(component);
layout.setActiveItem(id);
queue.unshift(id);
if (this.items.getCount() > this.bufferSize) {
var itemToRemove = queue.pop();
this.remove(itemToRemove);
}
}
document.title = component.title;
};
FN.COMMON.ContentContainer.superclass.initComponent.apply(this, arguments);
}
});

Ext.reg('contentcontainer', FN.COMMON.ContentContainer);











FN.COMMON.FNApp = function() {

var getActionPanelItems = function() {
var items = [{
xtype : 'panel',
frame : true,
title : 'Menu',
collapsible : true,
html : FN.COMMON.Templates.menuListTpl.applyTemplate([{
id : 'timesheetsLink',
label : 'Item A',
href : 'A'
},{
id : 'reportsLink',
label : 'Item B',
href : 'B'
},{
id : 'reportsHolidayRequestLink',
label : 'Item C',
href : 'C'
},{
id : 'changeLogLink',
label : 'Item D',
href : 'D'
},{
id : 'currentActivityLink',
label : 'Item E',
href : 'E'
},{
id : 'editUserLink',
label : 'Item F',
href : 'F'
}]),
titleCollapse : true
}];
return items;
}


var buildViewport = function() {

new Ext.Viewport({
layout : 'border',
id : 'viewport',
items : [
{
region : 'west',
xtype : 'panel',
split : true,
width : 220,
id : 'action-panel',
collapsible : true,
collapseMode : 'mini',
border : false,
baseCls : 'x-plain',
items : getActionPanelItems()
},{
xtype : 'contentcontainer',
region : 'center',
id : 'contentContainer',
ref : 'contentContainer'
}]
});

selectContentPanel();
};

var selectContentPanel = function(token) {
token = token ? token : Ext.History.getToken();
// Restore the UI to the appropriate history state
var parts, subparts, xtype;
var contentContainer = Ext.getCmp('viewport').contentContainer;
var layout = contentContainer.getLayout();
if(token){
parts = token.split(FN.COMMON.Util.tokenDelimiter);
//TODO: handle invalid tokens (malformed URLs)
xtype = parts[0];
contentContainer.swapPanel(xtype);
subparts = parts.slice(1);
} else {
//no token means user opened page without hash in url or
//navigated back to the first page, where there is no hash in url
contentContainer.swapToDefaultPanel();
}
};

return {
// public members
init : function() {
Ext.History.init();
Ext.History.on('change', selectContentPanel);
buildViewport();
}
};

}();

Ext.onReady(FN.COMMON.FNApp.init, FN.COMMON.FNApp);

</script>

</head>
<body>
<!-- Fields required for history management -->
<form id="history-form" class="x-hidden">
<input type="hidden" id="x-history-field" />
<iframe id="x-history-frame"></iframe>
</form>
</body>
</html>

Plasma
1 Oct 2009, 8:25 PM
I've just hit this problem myself, ExtJS 3.0.0

gallinari.marco
1 Dec 2009, 5:07 PM
I'm trying to add history to my application and I'm spotting this issue, too.

In my implementation, History token change triggers an Ajax call which results are used to create a new viewport for each call, overwriting the previous viewport.

In FF it all works fine, but in IE 8 (and in compatibility mode, too) history is almost always closed in a sort of loop. Pressing back button once takes me to the previous viewport correctly, but forward button doesn't enable, and pressing back button once again, the browser acts like stepping FORWARD in history; further, clicking on back button lead to a back-forward loop.

Anyone got clues about that?

mrpip
15 Jan 2010, 3:48 AM
I've also just run into this bug in IE8 and Ext JS 3.0.0, has anyone made any progress with it?

g.sidler
1 Mar 2010, 2:39 AM
I observe similar issues. I tried the example application at http://www.extjs.com/deploy/dev/examples/history/history.html. That works well in FF and IE7.
Then, I more or less copied that example code to my application. In FF everything works fine. In IE7 the back and forward button behave very strangely. I registered a 'change' event handler with Ext.History. Then, when I press the browser's back button sometimes the change event handler is called and sometimes not. Most of the time I need to press the back button three times to get one change event triggered. Furthermore, after I move back several steps, I cannot move forward anymore. The forward history is gone and the forward button disabled.

Another strange thing in IE7: Inside the Ext.onReady() function I tried to add a history record using the Ext.History.add() function. This call to the add() function is ignored in IE7. There is no error message but nothing happens to the history. Only after the user starts interacting with the application, e.g. by clicking somewhere, can I successfully add a history step.

Really puzzling is that the example application works well but the same code inside my application doesn't work. Other people seem to have made the same experience. Maybe the functioning of the Ext.History class in IE depends on other aspects of the application? What could that be??

Best regards, Gabe

ts-gbtec
14 Mar 2011, 4:05 AM
Is there any progress on this topic? I've the same problem in my application now.

Using ExtJS 3.2.2

ts-gbtec
16 Mar 2011, 1:51 PM
I've to ask again because this one is really bothering me. Has anyone a hint how to get the history work with IE?

devtig
4 Jul 2011, 12:48 AM
Try and run this in IE7, IE8 Ext JS 3.3.1 through 3.4.0. You won't see a back button after clicking on the button. Why?


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Where is IE back button?</title>
<link rel="stylesheet" type="text/css" href="/extjs/3/3/1/resources/css/ext-all.css"/>
<script type="text/javascript" src="/extjs/3/3/1/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="/extjs/3/3/1/ext-all.js"></script>
<script type="text/javascript">
Ext.onReady(function() {
Ext.History.init();

var panel=new Ext.Panel({
title: 'Message Title',
renderTo: Ext.getBody(),
width: 200, height: 130,
defaultType: 'box',
items: {
xtype: 'button',
text: 'Go to thanks',
handler: function() {
Ext.History.add('thanks');
}
}
});

Ext.History.on('change', function(token) {
panel.add({
html: 'history change: '+token
});
panel.doLayout();
});
});
</script>
</head>
<body>
<!-- Fields required for history management -->
<form id="history-form" class="x-hidden">
<input type="hidden" id="x-history-field" />
<iframe id="x-history-frame"></iframe>
</form>
</body>
</html>

skirtle
5 Jul 2011, 1:36 PM
It seems to help if you add a doctype. I tried it with this and it fixed it:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

wrowan
23 Feb 2013, 9:53 AM
Did anyone find a solution to this?

We are having a similar problem and can't find any solution.

I have a pretty thorough write-up here:

http://stackoverflow.com/questions/15042460/back-button-using-extjs-3-4-history-with-ie8-ie9-standards-document-mode
(http://stackoverflow.com/questions/15042460/back-button-using-extjs-3-4-history-with-ie8-ie9-standards-document-mode)
The net is that I can't get the Ext History utility to work more than once with the browser back button when running in IE in Standard Document mode for versions 8 and higher. If I traverse from page1 to page2 to page3, then hit the back button twice, I end up on page3, not page1.

The History example that Sencha has posted exhibits this behavior, however, it is masked because Quirks mode is the page default.

Any hints or thoughts would be tremendously appreciated.

wrowan
26 Feb 2013, 5:38 AM
This was actually pretty straightforward. I downloaded Ext 4.1 and looked at what they were doing with the Ext.util.History class. They define a variable for oldIEMode and use that for all the conditionals where in 3.4 they are using Ext.isIE.
So I edited the Ext.History class in ext-all-debug.js and defined the following variable at the top:
var oldIEMode = Ext.isIE6 || Ext.isIE7 || !Ext.isStrict && Ext.isIE8;
There were three conditionals in the class that were checking for Ext.isIE which I replaced with oldIEMode.

I ended up overriding the class rather than editing the ext-all.js file. My full solution is posted on the stackoverflow question thread.