Deep Linking
From Frontal Wiki
Contents |
Introduction
Deep linking is a technique by which changes in your Frontal document can result in changes in your browser's address bar and title. It can also work the other way around where changes in your browser's address bar affect the Frontal document. As a result, managed elements, video cue points and other elements in your Frontal document may have their own URLs such that when visited will bring those elements to the fore without your visitor having to navigate to them. Also with deep linking, the browser's previous and next buttons can be used to move around the navigated elements of your document.
Frontal uses the SWFAddress JavaScript/Actionscript library as the basis for its deep linking functionality though it is not necessary to know about this package's capabilities in order to use it. As we shall see, deep linking with Frontal is an easy process.
Turning on Deep Linking
We turn on deep linking with the deep-link style. It's value can either be "path," "query" or "none" though keep in mind that only one element among all the Frontal documents that may be loaded on an HTML page may use the "path" value. This is because there's only one address bar!
There is automatic support for this style on 'video' and 'manager' tags. But through interactions, you may add deep linking capabilities to any element. We shall see examples of these cases below.
Deep-Linked Managed Elements
'manager' tags are particularly suited for deep linking since they impart a notion of being selected to a Frontal element. In this example, we create a simple sectioned site with deep linking enabled. Run the following code sample.
<style><![CDATA[ * { style-tween-ease: fl.transitions.easing.Regular.easeOut; style-tween-duration: 6; style-tween-use-secs: false; } .section { width: 470px; height: 220px; padding: 40px; color: #ffffff; font-size: 24; } .sectionButtons { float: left; width: 112px; padding: 4px; border-width: 1px; background-color: orange; margin-right: 4px; } .menuEntry { width: auto; height: 0px; alpha: 0; } .menuEntry:link { color: #666666; } .menuEntry:visited { color: #999999; } .menuEntry:focus, .menuEntry:hover { color: #cccccc; underline: true; } .menuEntry:active { color: red; } .menuEntry:selected { color: black; underline: false; } .menuEntry:selected, .menuEntry:siblingSelected, .menuEntry:parentSelected(1), .menuEntry:childSelected, .menuEntry:nephewSelected { alpha: 1; height: 18px; } ]]></style> <div style="width: 100%;"> <div class="sectionButtons"> <text class="frMarker menuEntry" mgrId="mgr" elemNdx="Section One">Section 1</text> <text class="frMarker menuEntry" mgrId="mgr" elemNdx="Section One: Sub Section One" style="padding-left: 4px;">Section 1.1</text> <text class="frMarker menuEntry" mgrId="mgr" elemNdx="Section One: Sub Section Two" style="padding-left: 4px;">Section 1.2</text> </div> <div class="sectionButtons"> <text class="frMarker menuEntry" mgrId="mgr" elemNdx="Section Three">Section 3</text> </div> </div> <div style="layout: stack; left: 0px; top: 100px; width: 550px; height: 300px; overflow: hidden;"> <manager id="mgr" style="deep-link: path; hide-unselected: true; tween-container-init: true;"> <transitioner custom="com.frontalcode.transitions.TweenTransition" target="current" property="top" start="0" finish="300" duration="15" /> <transitioner custom="com.frontalcode.transitions.TweenTransition" target="next" property="top" start="-300" finish="0" duration="15" /> </manager> <text name="Section One" class="section" style="background-color: blue;"><![CDATA[Section One]]></text> <text name="Section One: Sub Section One" class="section" style="background-color: orange;" parentElemNdx="Section One"> <![CDATA[Section One: Sub Section One]]> </text> <text name="Section One: Sub Section Two" class="section" style="background-color: teal;" parentElemNdx="Section One"> <![CDATA[Section One: Sub Section Two]]> </text> <text name="Section Three" class="section" style="background-color: green;"><![CDATA[Section Three]]></text> </div>
The key thing to note in this example is the style "deep-link: path;" on the 'manager' tag. This is all we needed to do to add deep linking. In the rendered page, select a few sections in the menu. Notice how the browser's address bar changes as you do. Also notice how the browser's title changes.
Now use the browser's back button. See how the section changes to whichever one was previously selected. Use the forward button to return to where you were.
When you first came to the published page, "Section One" was selected. Now go to "Section Three" and hit your browser's reload button. Choose to resend the submitted data. Notice how now when the Frontal document loads, "Section Three" is the first one to show. Go ahead and edit the address bar by hand changing "Section Three" to "Section One" and hit return. The section automatically changes!
Multiple Deep-Linked Elements
With Frontal and SWFAddress, it's easy to deep link multiple elements at once. As we noted earlier, we can only have a single element with the deep-link style set to "path" but we may have many set to "query." This is because query-based deep linking uses specially named URL parameters that don't collide with one another to indicate the state of the deep link.
In this example, we have three slide shows. (Click the images to change the slides.) The first slide show uses "path" deep linking and the other two use the "query" method.
<style><![CDATA[ img { width: 160px; height: 120px; } ]]></style> <div style="layout: stack; float: left; margin: 10px;"> <manager id="mgr1" style="deep-link: path; hide-unselected: true;" /> <img mgrId="mgr1" class="frButtonNext" src="assets/images/image_1.jpg" /> <img mgrId="mgr1" class="frButtonNext" src="assets/images/image_2.jpg" /> <img mgrId="mgr1" class="frButtonNext" src="assets/images/image_3.jpg" /> </div> <div style="layout: stack; float: left; margin: 10px;"> <manager id="mgr2" style="deep-link: query; hide-unselected: true;" /> <img mgrId="mgr2" class="frButtonNext" src="assets/images/image_1.jpg" /> <img mgrId="mgr2" class="frButtonNext" src="assets/images/image_2.jpg" /> <img mgrId="mgr2" class="frButtonNext" src="assets/images/image_3.jpg" /> </div> <div style="layout: stack; float: left; margin: 10px;"> <manager id="mgr3" style="deep-link: query; hide-unselected: true;" /> <img mgrId="mgr3" class="frButtonNext" src="assets/images/image_1.jpg" /> <img mgrId="mgr3" class="frButtonNext" src="assets/images/image_2.jpg" /> <img mgrId="mgr3" class="frButtonNext" src="assets/images/image_3.jpg" /> </div>
As you click leftmost slideshow, see how the url's path parameter changes. As you click the other two, see how the url parameters change. The url parameters come in threes: one to identify the document of the deep-linked element, one to identify the manager and one to identify the selected element.
Now as you click the browser's previous and next buttons, see how it's like stepping backwards and forwards through a history of clicks on the three slide shows. And also note that if you refresh the browser, all three slide shows maintain their selection.
Deep-Linked Video
We can use cue points on a 'video' tag to create deep links into videos. For details, see the section on video deep linking.
Interactions and Methods for Custom Implementations
Any Frontal element, not just 'video' and managed elements, may support deep linking through Frontal interactions. Here are the interactions available for this purpose:
- onGetDeepLinkValue: Called when a deep link value in the URL is being resolved. The value in the URL will be passed to this interaction as the predefined variable "index". This interaction should then return whatever value is associated with "index". For example, a 'manager' with "deep-link" set to "query" will treat "index" as a numeric value and return the corresponding managed DocumentElement.
- onGetDeepLinkIndex: This interaction is called when the inverse operation of onGetDeepLinkValue is needed. That is, we have a value that is associated with a deep link and want to know what that deep link might be. The value of interest is passed to the interaction as the pre-defined variable "value". For example, a 'manager' with deep-link set to "path" would return the URL path of a managed element passed in as the "value."
- onProcessDeepLink: After the interaction "onGetDeepLinkValue" processes an index from the URL, the returned value must be acted on. This interaction handles that piece of the puzzle. A pre-defined variable named "value" is the return from the "onGetDeepLinkValue" interaction. So for a "manager" object for example, this interaction would call its "jumpTo" method with the value parameter (a DocumentElement) as its argument.
In addition, there are these methods available to all Frontal elements:
- getDeepLinkValue: The equivalent of the onGetDeepLinkValue interaction described above, it returns a value for a given index. It takes a single parameter:
- index: The index for which a value is desired.
- getDeepLinkIndex: The equivalent of the onGetDeepLinkIndex interaction described above, it returns an index for a given value. It takes a single parameter:
- value: The value for which an index is desired.
- processDeepLink: The equivalent of the onProcessDeepLink interaction described above, it performs some action based on a deep link. It takes a single parameter:
- value: The value associated with the deep link.
- checkForDeepLink: This serves a few purposes. First, it registers the element with the DeepLinkManager such that if there are changes to the URL, it may be notiifed. And second, it checks to see if there is currently a deep link value to act on. As such, it is typically used as part of an initialization process for the element. It takes no parameters and returns the deep link value associated with this element or undefined.
Finally, this method on the DeepLinkManager itself lets it know when a change has occurred in the Frontal document that should affect the browser's URL:
- com.frontalcode.DeepLinkManager.updateDeepLink: Called when a deep-linked element changes state and so affecting the browser's URL. This method takes these parameters:
- element: The element associated with the deep link.
- index: The new index for the deep link.
- title: If non-null and deep-link is set to "path" for the element, then this value will be used to set the browser's title.
Here then is an example using these interactions and methods to add custom deep linking to an element. Here, we are deep linking the background color of a 'div'. Click the 'div' to change its background color and then use the browser buttons to move backwards and forwards through these colors.
<style><![CDATA[ div { margin: auto; width: 25%; height: 25%; background-color: green; deep-link: path; @onFirstDocumentPreRender { var value = checkForDeepLink ( ); if ( value == null ) { // No initial value so set one. com.frontalcode.DeepLinkManager.updateDeepLink ( this, gS ( 'background-color' ), null ); } else { // Use the initial value in the URL. sS ( 'background-color', value ); } } @onClick { // Change our background color and notify the DeepLinkManager // so it can change the URL. sS ( 'background-color', Math.floor ( 0xffffff * Math.random ( ) ) ); com.frontalcode.DeepLinkManager.updateDeepLink ( this, gS ( 'background-color' ), null ); } @onGetDeepLinkValue { // Our index (the string in the URL) and the value it is // associated with (a value for the background-color style) are // the same in our case so we just return the passed-in index. return index; } @onGetDeepLinkIndex { // Our index (the string in the URL) and the value it is // associated with (a value for the background-color style) are // the same in our case so we just return the passed-in value. return value; } @onProcessDeepLink { // There has been a deep-link change. Set our background color // based on the new value. if ( value != null ) sS ( 'background-color', value ); } } ]]></style> <div />