O'Reilly    
 Published on O'Reilly (http://oreilly.com/)
 See this if you're having trouble printing code examples


Understanding the BrowserManager Class and Deep Linking - Search Engine Optimization for Flash

by Todd Perkins

One way you can enable two-way communication between the browser and your Flex applications is when you use the BrowserManager class. The BrowserManager class lets you capture and use URL fragments—name value pairs used as named anchors. This ability lets you update a Flex application based on its URL. It also lets you update URLs based on Flex input, so just like using SWFAddress in Flash, you can create two-way communication between your Flex application and the web browser.

Search Engine Optimization for Flash book cover

This excerpt is from Search Engine Optimization for Flash. Search Engine Optimization for Flash dispels the myth that Flash-based websites won't show up in a web search by demonstrating exactly what you can do to make your site fully searchable -- no matter how much Flash it contains. You'll learn best practices for using HTML, CSS and JavaScript, as well as SWFObject, for building sites with Flash that will stand tall in search rankings.

buy button

Understanding the BrowserManager Class and Deep Linking

BrowserManager Essentials

Before you begin using the BrowserManager class to control two-way communication between the browser and your Flex application, it’s important to understand how the BrowserManager class works. This section explains the important parts of working with the BrowserManager class that you should be familiar with before implementing it in your applications.

Properties, methods, and events

Look at the BrowserManager properties, methods, and events you’ll be working with for the BrowserManager example. Table 6.1, “BrowserManager properties, methods, and events” is a brief list of the BrowserManager class’s features. For more features, see Flex Help.

Table 6.1. BrowserManager properties, methods, and events

Name Type Description
Fragment Property An object that holds the fragment portion of the current URL—data type is string
BrowserManager.getInstance() Method (Static) Returns an IBrowserManager instance
setTitle() Method Sets the browser’s title
setFragment() Method Sets the fragment of the current URL
BrowserChangeEvent.BROWSER_URL_CHANGE Event Triggered when the browser’s URL is changed

Using the URLUtil class

Since the BrowserManager uses strings only as a data type for getting and setting URL fragments, in order to access the fragment values of the string, you need to do some processing. For example, a fragment string may be view=1, and in order to use the data you have to separate the property (view) from the value (1).

That’s where the URLUtil class comes in. Using the URLUtil class helps you skip the step of processing strings, and gives you easy object access to fragment properties and values. It converts strings to objects for processing fragments using its stringToObject() method, and converts objects to strings for sending fragments using its objectToString() method. That way, you can use an object to represent the fragment and access its property names and values using object notation. For example, you can get the value of the view fragment through your fragment’s view property, so the code would be fragment.view.

Creating a Deep Linking Application

Now you’ll look at using the BrowserManager class to build an application that uses two-way deep linking. Here’s a complete application that uses this technique:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="initApp()">
<mx:Script>
    <![CDATA[
        import mx.managers.IBrowserManager;
        import mx.managers.BrowserManager;
        import mx.events.BrowserChangeEvent;
        import mx.utils.URLUtil;

        import mx.controls.Text;
        import mx.containers.VBox;

        private var req:URLRequest = new URLRequest("data.xml");
        private var loader:URLLoader = new URLLoader();
        private var xmlData:XML;

        private var manager:IBrowserManager;

        private function initApp():void
        {
            manager = BrowserManager.getInstance();
            manager.addEventListener(BrowserChangeEvent.BROWSER_URL_CHANGE,
parseURL);
            manager.init("","Wedgekase Wii Games");
            loader.addEventListener(Event.COMPLETE,loadComplete);
            loader.load(req);
        }

        private function loadComplete(event:Event):void
        {
            xmlData = new XML(loader.data);
            for each(var game:XML in xmlData.game)
            {
                var vbox:VBox = new VBox();
                var field:Text = new Text();
                field.text = game.description;
                vbox.label = game.title;
                navigator.addChild(vbox);
                vbox.addChild(field);
                field.width = 375;
                field.height = 100;
            }
        }

        private function parseURL(event:BrowserChangeEvent):void
        {
            var fragment:Object = URLUtil.stringToObject(manager.fragment);
            if(fragment.view == undefined)
            {
                fragment.view = 0;
            }
            navigator.selectedIndex = fragment.view;
            manager.setTitle(xmlData.game[navigator.selectedIndex].title);
        }

        private function updateURL():void
        {
            var newFragment:Object = {};
            var fragmentStr:String = "";
            newFragment.view = navigator.selectedIndex;
            fragmentStr = URLUtil.objectToString(newFragment);
               manager.setFragment(fragmentStr);
               manager.setTitle(xmlData.game[navigator.selectedIndex].title);
        }
    ]]>
</mx:Script>
    <mx:TabNavigator id="navigator" width="400" height="150" change=
"updateURL()">
    </mx:TabNavigator>

</mx:Application>

Take a look at how this application uses the BrowserManager class. First, note that it’s the same application you used in the last section, with a few updates. The first update is the extra import statements:

import mx.managers.IBrowserManager;
import mx.managers.BrowserManager;
import mx.events.BrowserChangeEvent;
import mx.utils.URLUtil;

These statements import the necessary classes for working with the BrowserManager class. Note the IBrowserManager class is imported, because an instance of IBrowserManager will be used to work with the BrowserManager because the BrowserManager class is a type of class that never gets instantiated.

The only new variable is manager, which is data typed to be an instance of any class that implements the IBrowserManager interface:

private var manager:IBrowserManager;

Note

An interface is a list of methods. Any class that implements an interface must contain all the methods in that interface. See Essential ActionScript 3.0 by Colin Moock for more details.

Next, look at the initApp() function:

private function initApp():void
{
    manager = BrowserManager.getInstance();
    manager.addEventListener
    (BrowserChangeEvent.BROWSER_URL_CHANGE, parseURL);
    manager.init("","Wedgekase Wii Games");
    loader.addEventListener(Event.COMPLETE,loadComplete);
    loader.load(req);
}

The initApp() function has three new lines of code. First, the manager variable is set to BrowserManager.getInstance(), which returns an instance that implements IBrowserManager. Next, an event listener is added to the manager instance, listening for the browser’s URL to change. Upon changing, the parseURL() function runs. Finally, the BrowserManager is initialized using its init() method. The first parameter represents the initial URL fragment, which is left blank here. The second represents the initial browser title.

Now you’ll discuss the parseURL() function:

private function parseURL(event:BrowserChangeEvent):void
{
    var fragment:Object = URLUtil.stringToObject(manager.fragment);
    if(fragment.view == undefined)
    {
        fragment.view = 0;
    }
    navigator.selectedIndex = fragment.view;
    manager.setTitle(xmlData.game[navigator.selectedIndex].title);
}

This function gets triggered when the browser’s URL changes. First, the fragment object uses the URLUtil to convert the manager’s fragment from a string to an object. Then, if the view property of the fragment is undefined, it is set to 0. Then, the navigator’s selected index is set to whatever value is in the fragment’s view property, which updates the TabNavigator according to the current URL fragment. Finally, the page’s title is updated using the manager’s setTitle() method. The title is set to the value of the game title that corresponds to the current selected index of the TabNavigator component (which was previously received from the URL fragment).

So far you’ve looked at what happens when the URL is updated, but not at what makes a change in the URL. The first thing that initiates the change is the change event of the TabNavigator, which is set to run the updateURL() function:

<mx:TabNavigator id="navigator" width="400" height="150" change="updateURL()">
</mx:TabNavigator>

The updateURL() function looks like this:

private function updateURL():void
{
    var newFragment:Object = {};
    var fragmentStr:String
    newFragment.view = navigator.selectedIndex;
    fragmentStr = URLUtil.objectToString(newFragment);
    manager.setFragment(fragmentStr);
    manager.setTitle(xmlData.game[navigator.selectedIndex].title);
}

First, this function creates a new empty object to represent the new fragment that will appear in the URL (newFragment) and a new empty string that will represent the string version of newFragment (fragmentStr). Next, the newFragment object’s view property is set to the selected index of the TabNavigator (i.e. the index number of whatever tab was clicked to initiate the change event). Then, a string version of the newFragment object is held in fragmentStr, and set as the current fragment using the BrowserManager’s setFragment() method. Finally, the page’s title is set to the current game’s title from the XML file.

You need a server to test this application’s two-way communication. The files in the history folder created by Flex Builder should also be copied to your server, since they’re the supporting files that control communication between the browser and the Flex application. When testing this file on your server, click through the tabs to watch the URLs update (Figure 6.13, “Viewing the BrowserManager class in two-way communication action.”), and change the view number in the URL to watch the application update.

Figure 6.13. Viewing the BrowserManager class in two-way communication action.

Viewing the BrowserManager class in two-way communication action.

BrowserManager Limitations

Though the BrowserManager class is a powerful tool for two-way communication between the browser and the application, it’s lacking an important SEO feature. The problem with the BrowserManager class as you’ve used it here is that in order to navigate to an application state, the application must first be initialized. That means, if you pass in a fragmented URL to your application, desiring to start on view 2, the application would start at view 0. Once at view 0, the application can then be moved to view 2 via a URL change. Even though this feature allows two-way communication, and with an extra step allows for saving URLs, you’re still better off going with a system like SWFAddress for deep linking.

Note

Deep linking in Flex is possible without using SWFAddress or any third party code, but it’s more complex than the example shown here. For information about deep linking in Flex that supports fragment URLs when an application is first initialized, in Flex Help, see Deep Linking.

The BrowserManager class doesn’t work in every web browser. Currently, the BrowserManager class is not supported by Safari, Chrome, or Opera. This doesn’t harm how spiders index your site, but it can decrease traffic on your site for anyone using those browsers, so it’s best to use SWFAddress or another method that’s more broadly supported.

If you enjoyed this excerpt, buy a copy of Search Engine Optimization for Flash. .

Copyright © 2009 O'Reilly Media, Inc.