fixing deep linking for browsers like chrome
mxml file
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml”
layout=”vertical”
addedToStage=”this.onStageReady(event);”
creationComplete=”this.onAppComplete(event);” width=”200″ height=”200″
>
<mx:Script>
<![CDATA[
import mx.managers.BrowserManager;
import mx.events.BrowserChangeEvent;
import mx.events.FlexEvent;
import mx.managers.IBrowserManager;
private var bm:IBrowserManager;
private var hashTimer:Timer;
private var hashValue:String = "";
private function onAppComplete( event:FlexEvent ):void
{
this.hashTimer = new Timer( 500 );
this.hashTimer.addEventListener( TimerEvent.TIMER, this.onHashTimer );
this.bm = BrowserManager.getInstance();
this.bm.init( "", "Site" );
this.bm.addEventListener( BrowserChangeEvent.BROWSER_URL_CHANGE, this.onBrowserChange );
this.bm.addEventListener( BrowserChangeEvent.APPLICATION_URL_CHANGE, this.onAppChange );
}
private function onStageReady( event:Event ):void
{
this.setHash( this.bm.fragment );
this.setHashTimer();
}
private function setHashTimer():void
{
//inmediately call to detect if the anchor has a value.
this.onHashTimer();
if( !this.hashTimer.running )
this.hashTimer.start();
}
private function setHash( value:String ):void
{
this.hashValue = value;
txt.text = "hash value: " + this.hashValue;
}
private function getHash():void
{
var hash:String = ExternalInterface.call( "getHash" );
ExternalInterface.call( "alert", "Javascript.getHash() returns " + hash );
}
private function onBrowserChange( event:BrowserChangeEvent=null ):void
{
/**
* i noticed that chrome on first chrome change was getting a null value
* for browsermanager's fragment. so that was a good key for me to set the
* timer and read the anchor value coming from javascript.
*
* if i am able to get the fragment, then it means the browser works fine
* and i don't need to use my timer. but if the fragment value is null then
* i can set it back to use the timer.
*/
if( this.bm.fragment )
{
if( this.hashTimer.running )
this.hashTimer.stop();
this.setHash( this.bm.fragment );
}
else
{
this.setHashTimer();
}
}
/**
* if the application can handle browse changes by the browser, i wanted to keep this
* functionality independent from the browser making the changes instead */
private function onAppChange( event:BrowserChangeEvent ):void
{
this.setHash( this.bm.fragment );
}
/**
* checkign if the hash value has changed, and making sure we have the JS function available
* to retrieve the hash value **/
private function onHashTimer( event:TimerEvent=null ):void
{
var hash:String = ExternalInterface.call( "getHash" );
if( hash != this.hashValue )
{
this.setHash( hash );
}
}
/**
* this function was done in purpose to test what would happen in chrome if we
* change the hash value from the application instead of the browser */
private function linkHash():void
{
this.bm.setFragment( "1" );
}
]]>
</mx:Script>
<mx:Text id=”txt” width=”100″ height=”40″ text=”hello” />
<mx:Button label=”getHash” click=”this.getHash();” />
<mx:Button label=”setHash(1)” click=”this.linkHash();” />
</mx:Application>
page
<head>
<link rel=”stylesheet” type=”text/css” href=”/styles/history.css” />
<title></title>
<meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1″ />
<script type=”text/javascript” src=”/scripts/swfobject.js”></script>
<script type=”text/javascript” src=”/scripts/history.js”></script>
</head>
<body>
<div id=”AppLayer”>
<a href=”http://www.adobe.com/go/EN_US-H-GET-FLASH”>Get Flash Player</a> to view animation.
<script type=”text/javascript”>
//function required for getting the current hash
function getHash()
{
return unescape(self.document.location.hash.substring(1));
}
var requiredMajorVersion = 9;
var requiredMinorVersion = 0;
var requiredRevision = 124;
//swfobject
var flashvars = {};
var params = {};
params.menu = “false”;
params.quality = “best”;
params.scale = “noscale”;
params.salign = “tl”;
params.bgcolor = “#FFFFFF”;
params.allowscriptaccess = “always”;
var attributes = {};
swfobject.embedSWF(“/Main.swf”,
“AppLayer”,
“200″,
“200″,
“9″,
“/common/swf/expressInstall.swf”,
flashvars, params, attributes );
</script>
</div>
<a href=”#2″><p id=”2″>hash 2</p></a>
<a href=”#3″><p id=”3″>hash 3</p></a>
<a href=”#4″><p id=”4″>hash 4</p></a>
<a href=”#5″><p id=”5″>hash 5</p></a>
</body>
Thank you very much for your effort. I’ve tested this solution after I got some problem with Google Chrome.
Modified the default generated html wrapper (by flex 4) just extended with your getHash() function. Everything is working fine with tested in Chrome/IE7/IE8/Firefox/Safari/Opera
Thanks a lot, keep up the good work.
Thank you for your comment. I am going to moving to my own wordpress so i can have this word running to be easier. i hope my code wasn’t confusing..
The above approach works nicely, with the caveat that in fact, the whole timer is unnecessary. As you write in your code comment, the key is to detect that bm.fragment == null in onBrowserChange handler. All you need to do is call the getHash method from javascript in this case and forward it to the bm.setFragment method. The rest can be skipped, actually.
2
3
4
5
6
7
8
9
private function onBrowserChange( event:BrowserChangeEvent=null ):void
{
if( this.bm.fragment == null )
this.bm.setFragment(ExternalInterface.call( "getHash" ));
// continue using value of bm.fragment
}
thanks Veiko, i will give it a try.
i haven’t touch this solution in two years. i thought maybe by now google chrome had solved it
Not working for me.
Is BROWSER_URL_CHANGE message handler is called when user clicks the back button?
It seems not… would appreciate any help. Thanks.
hi, i am surprised that Flex still is missing this problem solved. My solution was written maybe three years ago. Hmm… I remember there was a timer in place so that it could detect the change you mentioned. There was a previous comment left regarding no need for the timer, did you do that as well, and maybe that’s why it’s not working for you.