Include

From Frontal Wiki

Jump to: navigation, search

Contents

Introduction to the include tag

The "include" tag is used to load some external resource into the Frontal definition. We will see how it can be used to "inline" external code and we will also see how we use it to import external resource SWFs.

Implementation

The include tag is implemented with the DocElemInclude class which extends the DocumentElement class.

Attributes

These attributes are particular to the include tag:

  • rel: "rel" stands for relationship and has the value "inline," "alt" or "assets." If "inline" then the results of the include will be written into the document just after the include tag. (The include element will remain in the XML definition.) If "alt" then the included file contains alternate content (see the 'alt' tag) and will only be loaded by the SEO Converter. If "assets" then the External Asset Manager is used to load the result. This manager is used to load assets in a priority queue. More details are available in the Advanced Topics section.
  • type: One of "text/css," "text/xml," or "application/x-shockwave-flash." This is currently unused.
  • blocking: If "rel" is "assets" then setting this attribute "true" will stop the Frontal renderer from parsing anymore of the document definition until the asset is loaded.
  • src: The URL of the external asset.
  • fontClasses: When "rel" is "assets," a comma separated list of Font class names to look for in the external SWF. See the "text" tag for examples.

Styles

The include tag particularly uses these styles:

  • base-url: The base URL to apply to the src attribute. base-url is a cascading style and so may be applied on, say, the document element to affect all include tags.
  • check-policy-file: Whether to try to load a Flash policy file for the external resource. The default is false.
  • policy-file-url: Where to look for the policy file if not at the root level of the asset's domain.
  • load-in-current-app-and-sec-domains: Whether to load the external asset in the Frontal renderer's application and security domains. See the Flash Security class for more details.


Inlining External Code

One use of the include tag is to "inline" one Frontal definition into another. For example, in the description of the "style" tag, we showed how the include tag could be used to pull in an external file whose contents were a single style tag. Well, that is just a limited case of what the include tag can do.

Let's say that we had a file named "square.xml" that contained this Frontal definition snippet. (Content for inlining must always be a valid Frontal definition with all tags closed.)

<style><![CDATA[
    document > div
        {
            width: 200px;
            height: 200px;
            float: left;
        }
    document > div > div
        {
            width: 100px;
            height: 100px;
        }
]]></style>
<div>
    <div style="background-color: red; float: left;" />
    <div style="background-color: green; float: left;" />
    <div style="background-color: blue; float: left;" />
    <div style="background-color: yellow; float: left;" />
</div>
<text>A Colorful Square</text>

We could then include this in our Frontal definition in an inline fashion wherever we wanted a colorful square. We could also define styles to manipulate the included content.

<style><![CDATA[
    document > div
        {
            width: 200px;
            height: 200px;
            float: left;
        }
    document > div > div
        {
            width: 100px;
            height: 100px;
        }
]]></style>
<include rel="inline" src="square.xml" />
<include rel="inline" src="square.xml" />
<include rel="inline" src="square.xml" />
<include rel="inline" src="square.xml" />

To test this sample out, you'll need to be able to post your square.xml file on some server that is accessible to the online workspace. You will also need to place a crossdomain.xml file on that server in order for Flash to access it. (See Permissions and External Assets below for more details.) And finally, you will want to set the "src" attribute in the include tags to the full URL of the square.xml file.

This example is probably not the best way to achieve this result. For example, the template tag could achieve this without the overhead of loading a file (even a cached file) four times. But it does illustrate how the inline functionality of the include tag works. Note that in order for inlining to work, Frontal must stop processing the Frontal definition while the external asset is loaded. Keep this mind as you use this tag.

Perhaps a more common use of the inlining functionality of the include tag is to pull in a scripting library. For example, there is a library for performing XML RPCs. This library is general purpose and so may be used by many Frontal definitions. To pull it in, these definitions use the include tag like so:

<include rel="inline" src="http://frontalcode.com/assets/xml/xmlrpc.xml" />

If you were to look at the contents of that file, it's simply a script tag inside of which is the definition of a class to help make XML RPC calls.


Including External Resource SWFs

Another use of the include tag is to load an external SWF for the resources it contains such as movie clips, fonts and ActionScript classes. For example, in our discussion of the "text" tag, we used the include tag to pull in SWFs that contained embedded fonts. That looked something like this:

<include rel="assets" type="application/x-shockwave-flash" src="http://www.frontalcode.com/assets/swfs/assets.swf" fontClasses="TrajanPro" />
<text style="font-family: Trajan Pro; font-size: 24px;">This text is in Trajan Pro.</text>

If you clear your browser's cache and submit this example from the online workspace, watch the text closely. It will first render in either the system default font or in an aliased version of Trajan Pro (if you have that font installed on your sytem) and then shortly thereafter it will re-render the text in an anti-aliased (smooth) way. What's happening is that at first the external resource is not available and Frontal does the best it can to render the text. But after the external resource is loaded, Frontal re-renders the text because it knows it can do better. To keep Frontal from rendering the text until the external resource is loaded, add the attribute "blocking" set to "true."

<include rel="assets" type="application/x-shockwave-flash" src="http://www.frontalcode.com/assets/swfs/assets.swf" fontClasses="TrajanPro" blocking="true" />
<text style="font-family: Trajan Pro; font-size: 24px;">This text is in Trajan Pro.</text>

In the previous section we showed one way to pull in a library of code. This technique was to pull in a script library that we could then use in our interactions. This is very handy and open but sometimes we want the extra performance boost of using compiled code or we want to use an AS3 library that isn't easily ported to the Frontal scripting language or that we don't have the source code to. In that case, we want to import the compiled class's into our Frontal definition for access by the Frontal scripts. We can do that with the include tag as well. For example, here we pull in a SWF which has the Google Maps AS3 API compiled into it:

<include rel="assets" type="application/x-shockwave-flash" src="http://www.frontalcode.com/assets/swfs/Gmaps.swf" blocking="true">
	<import>com.google.maps.Map</import>
	<import>com.google.maps.MapEvent</import>
	<import>com.google.maps.LatLng</import>
	<import>com.google.maps.MapType</import>
	<import>com.google.maps.MapOptions</import>
	<import>com.google.maps.MapMouseEvent</import>
	<import>com.google.maps.controls.ZoomControl</import>
	<import>com.google.maps.controls.PositionControl</import>
	<import>com.google.maps.controls.MapTypeControl</import>
	<import>com.google.maps.overlays.Marker</import>
	<import>com.google.maps.overlays.MarkerOptions</import>
</include>
<style><![CDATA[
	.map
		{
			@onFirstDocumentPreRender 
				{					
					dynamic.basikLatLng = new LatLng(40.745664,-73.988907);
 
					/* Functions must be declared before their references in the code block */
 
 
					dynamic.onMapReady = function (event) {
 
						// Add the usual array of controls
 
						dynamic.map.addControl(new ZoomControl());
						dynamic.map.addControl(new PositionControl());
						dynamic.map.addControl(new MapTypeControl());
 
						// Add a marker
 
						var marker = new Marker(dynamic.map.getCenter(), new MarkerOptions({draggable: true}));
 
						marker.addEventListener(MapMouseEvent.DRAG_START, function(event) {
							dynamic.map.closeInfoWindow();
						});
 
						marker.addEventListener(MapMouseEvent.DRAG_END, function(event) {
							var distance = marker.distanceFrom(dynamic.basikLatLng);
							var options = new InfoWindowOptions();
							options [ "content" ] = distance;
							dynamic.marker.openInfoWindow(new InfoWindowOptions({content:distance}));
						});
 
						dynamic.map.addOverlay(marker);
					}
 
 
					//	Set up map options for preinitialization to avoid loading the default view
					//	in addition to the initial target
 
					dynamic.onPreinitialize = function (event) {
 
						// setInitOptions is the only call available at preinit time
 
						var myMapOptions = new MapOptions();
						myMapOptions.zoom = 14;
						myMapOptions.center = new LatLng (40.736072,-73.992062);
						myMapOptions.mapType = MapType.NORMAL_MAP_TYPE;
						dynamic.map.setInitOptions(myMapOptions);
					}					
 
					// Instantiate our map
 
					dynamic.map = new Map();
 
					// Set the API key
 
					dynamic.map.key = "ABQIAAAAuV9Of761mXG7kAyhznSkjRSoiJB0_nJaPQ_HIU9YiGRu5S0O-RQ5ToogA0PPOjx_E1wrfOzbWzcmGA";
 
					// Add our listeners
 
					dynamic.map.addEventListener(MapEvent.MAP_PREINITIALIZE, dynamic.onPreinitialize);
					dynamic.map.addEventListener(MapEvent.MAP_READY, dynamic.onMapReady);
 
					// Insert the map into the div
 
					movie.addChildAt ( dynamic.map, 0 );
				}
			@onCustomRender
				{
					if ( dynamic.map != null )
					{
						dynamic.map.setSize ( new flash.geom.Point ( width, height ) );
					}
				}
		}
]]></style>
 
<div style="processes-own-content: true; width: 100%; height: 100%;" class="map">
</div>

With the "import" tag in the previous example (which is only valid as a child of an include tag), we are telling Frontal that after the external SWF loads, the given class should be imported into the global namespace for all scripts across all documents. We show this working with the script tag in our example which immediately after the include tag shows a message indicating that "Map" references an ActionScript class.

<include rel="assets" type="application/x-shockwave-flash" src="http://www.frontalcode.com/assets/swfs/Gmaps.swf" blocking="true">
    <import>com.google.maps.Map</import>
    <import>com.google.maps.MapEvent</import>
    <import>com.google.maps.LatLng</import>
    <import>com.google.maps.MapType</import>
    <import>com.google.maps.MapOptions</import>
    <import>com.google.maps.MapMouseEvent</import>
    <import>com.google.maps.controls.ZoomControl</import>
    <import>com.google.maps.controls.PositionControl</import>
    <import>com.google.maps.controls.MapTypeControl</import>
    <import>com.google.maps.overlays.Marker</import>
    <import>com.google.maps.overlays.MarkerOptions</import>
</include>
<script><![CDATA[
    com.frontalcode.Debugger.msg ( "Map = " + Map );
]]></script>

Note that we do not have to import a class in order to use it. We can also use the fully qualified class name like so:

<include rel="assets" type="application/x-shockwave-flash" src="http://www.frontalcode.com/assets/swfs/Gmaps.swf" blocking="true" />
<script><![CDATA[
    com.frontalcode.Debugger.msg ( "Map = " + com.google.maps.Map );
]]></script>

This way of importing with the blocking attribute is very handy because we can assume that the resource is loaded at any later point in our Frontal definition but it does mean that the Frontal definition will not parse or render while the external asset is loading. A more asynchronous approach is to not block on the include and then to either poll for the existence of the class or to register a callback for when it is loaded. For example:

<include rel="assets" type="application/x-shockwave-flash" src="http://www.frontalcode.com/assets/swfs/Gmaps.swf" />
<script><![CDATA[
    var mapClass = document.externalAssetManager.getDefinition ( "com.google.maps.Map", onLoadExternalAsset );
    com.frontalcode.Debugger.msg ( "mapClass = " + mapClass );
    function onLoadExternalAsset ( name, externalAssetSrc, classRef )
    {
        var markerClass = document.externalAssetManager.getDefinition ( "com.google.maps.overlays.Marker" );       
        com.frontalcode.Debugger.msg ( "loaded Map = " + classRef + ", Marker = " + markerClass );
    }
]]></script>

Here we show how we can query the External Asset Manager (see [Advanced Topics] for more details) for the class of interest. If it were available, we would get the class reference immediately but the Debugger message is showing that it's not. At the same time we query for the class, we can register a callback function which we do and which is called when the class of interest is loaded. Inside that callback we're showing the loaded class as well as showing how once the SWF is loaded, all of its internal classes are available.

An advantage of not using the blocking include is that it's load may be queued in order of priority. That is, if the include tag were part of a managed element, say, then it would sit at the bottom of the load queue until it were needed or everything else were loaded. The management of the load queue based on demand is simply part of Frontal but by making the include tag blocking, it makes the external resource no longer a candidate for that management. For more details, see Asset Queue Management in the Advanced Topics.


Building an External ActionScript Library SWF

When building a SWF to act as an external ActionScript library SWF, you must take care to ensure that the desired classes in your library are actually compiled and included in your SWF. One way to do this is to add ActionScript to the FLA of your external resource that simply references each class in your library. For example, in building a SWF from the AS3 Core Lib project ([1]) to decode JSON files, we used ActionScript like the following to be sure the classes were included in the resulting SWF:

import com.adobe.serialization.json.*;
var tmp : Class;
tmp = JSON;
tmp = JSONDecoder;
tmp = JSONEncoder;
tmp = JSONParseError;
tmp = JSONToken;
tmp = JSONTokenType;
tmp = JSONTokenizer;

This was using Flash CS3. There are other ways to do the same thing in CS4 without the bother.


SecurityError #2142

When running the Frontal renderer from the Flash IDE (if you have downloaded the source code and are building your own Frontal Renderer), you will notice that external resources loaded with the "load-in-current-app-and-sec-domains" style set to true will fail. This is because the Flash Security system does not allow a local resource to include a network resource into its security domain. The full error is:

SecurityError: Error #2142: Security sandbox violation: local SWF files cannot use the LoaderContext.securityDomain property.

There is no workaround we know of other than to publish the file in the IDE and then serve it through a web server.

Personal tools
Get Adobe Flash player