iFrame

// ———————————————————————–
// IFrame.as – Alistair Rutherford, http://www.netthreads.co.uk
// Glasgow, Scotland Oct 2007 .
// ———————————————————————–
// Revision Date Notes
// ——– —- —–
// 1.0 16/09/07 .Initial version
// 1.1 29/09/07 .Fixed bug where the frame wasn’t resizing itself
// when the source url was assigned.
// ———————————————————————–
// This component is based on the work of:
//
// Christophe Conraets
// http://www.coenraets.org
//
// and
//
// Brian Deitte
// http://www.deitte.com/archives/2006/08/finally_updated.htm
//
// ———————————————————————–
// I have made some additions to the original code
//
// – javascript support functions are now generated by the component and
// inserted directly into the DOM.
//
// – Component generates it’s own div and iframe element and inserts them
// into the DOM.
//
// – When the component is created the display list is traversed from the
// component down to the root element. At each traversal a test is made to
// see if current component is a container. If it is a container then the
// child of the element which leads back to the component is determined and
// a note madeof the appropriate ‘index’ on the path. The index is stored
// against a reference to the Container in a Dictionary. Also the container
// is ‘seeded’ with an event handler so that if the container triggers an
// IndexChangedEvent.CHANGE (i.e. when you click on a tab in a viewstack)
// the path of ‘index’ values down to the component can be checked. If the
// path indicates that the indexes ‘line up’ to expose the component then
// the view is made visible. I hope I have explained this correctly 🙂
// ———————————————————————–

package
{
import flash.geom.Point;
import flash.events.Event;
import flash.utils.Dictionary;
import flash.display.DisplayObjectContainer;

import mx.core.Container;
import mx.events.IndexChangedEvent;

import flash.external.ExternalInterface;

public class IFrame extends Container
{
private var __source: String;
private var frameId:String;
private var iframeId:String;

private var containerDict:Object = null;
private var settingDict:Object = null;

/**
* Here we define javascript functions which will be inserted into the DOM
*
*/
private static var FUNCTION_CREATEIFRAME:String =
“document.insertScript = function ()” +
“{ ” +
“if (document.createIFrame==null)” +
“{” +
“createIFrame = function (frameID)” +
“{ ” +
“var bodyID = document.getElementsByTagName(\”body\”)[0];” +
“var newDiv = document.createElement(‘div’);” +
“newDiv.id = frameID;” +
“newDiv.style.position =’absolute’;” +
“newDiv.style.backgroundColor = ‘transparent’;” +
“newDiv.style.border = ‘0px’;” +
“newDiv.style.visibility = ‘hidden’;” +
“bodyID.appendChild(newDiv);” +
“}” +
“}” +
“}”;

private static var FUNCTION_MOVEIFRAME:String =
“document.insertScript = function ()” +
“{ ” +
“if (document.moveIFrame==null)” +
“{” +
“moveIFrame = function(frameID, iframeID, x,y,w,h) ” +
“{” +
“var frameRef=document.getElementById(frameID);” +
“frameRef.style.left=x;” +
“frameRef.style.top=y;” +
“var iFrameRef=document.getElementById(iframeID);” +
“iFrameRef.width=w;” +
“iFrameRef.height=h;” +
“}” +
“}” +
“}”;

private static var FUNCTION_HIDEIFRAME:String =
“document.insertScript = function ()” +
“{ ” +
“if (document.hideIFrame==null)” +
“{” +
“hideIFrame = function (frameID)” +
“{” +
“document.getElementById(frameID).style.visibility=’hidden’;” +
“}” +
“}” +
“}”;

private static var FUNCTION_SHOWIFRAME:String =
“document.insertScript = function ()” +
“{ ” +
“if (document.showIFrame==null)” +
“{” +
“showIFrame = function (frameID)” +
“{” +
“document.getElementById(frameID).style.visibility=’visible’;” +
“}” +
“}” +
“}”;

private static var FUNCTION_LOADIFRAME:String =
“document.insertScript = function ()” +
“{ ” +
“if (document.loadIFrame==null)” +
“{” +
“loadIFrame = function (frameID, iframeID, url)” +
“{” +
“document.getElementById(frameID).innerHTML = \”<iframe id=’\”+iframeID+\”‘ src=’\”+url+\”‘ frameborder=’0’></iframe>\”;” +
“}” +
“}” +
“}”;

/**
* Constructor
*
*/
public function IFrame()
{
super();
}

/**
* Generate DOM elements and build display path.
*
*/
override protected function createChildren():void
{
super.createChildren();

if (! ExternalInterface.available)
{
throw new Error(“ExternalInterface is not available in this container. Internet Explorer ActiveX, Firefox, Mozilla 1.7.5 and greater, or other browsers that support NPRuntime are required.”);
}

// Generate unique id’s for frame div name
frameId = id;
iframeId = “iframe_”+frameId;

// Add functions to DOM if they aren’t already there
ExternalInterface.call(FUNCTION_CREATEIFRAME);
ExternalInterface.call(FUNCTION_MOVEIFRAME);
ExternalInterface.call(FUNCTION_HIDEIFRAME);
ExternalInterface.call(FUNCTION_SHOWIFRAME);
ExternalInterface.call(FUNCTION_LOADIFRAME);

// Insert frame into DOM using our precreated function ‘createIFrame’
ExternalInterface.call(“createIFrame”, frameId);

buildContainerList();
}

/**
* Build list of container object on the display list path all the way down
* to this object. We will seed the container classed we find with an event
* listener will be used to test if this object is to be displayed or not.
*
*/
private function buildContainerList():void
{
// We are going to store containers against index of child which leads down
// to IFrame item.
containerDict = new Dictionary();
settingDict = new Dictionary();

var current:DisplayObjectContainer = parent;
var previous:DisplayObjectContainer = this;

while (current!=null)
{
if (current is Container)
{
if (current.contains(previous))
{
var childIndex:Number = current.getChildIndex(previous);

// Store child index against container
containerDict[current] = childIndex;
settingDict[current] = childIndex;

// Tag on a change listener
current.addEventListener(IndexChangedEvent.CHANGE, handleChange);

}

}

previous = current;
current = current.parent;
}

}

/**
* Triggered by one of our listeners seeded all the way up the display
* list to catch a ‘changed’ event which might hide or display this object.
*
* @param event Event trigger
*
*/
private function handleChange(event:Event):void
{
var target:Object = event.target;

if (event is IndexChangedEvent)
{
var changedEvent:IndexChangedEvent = IndexChangedEvent(event)

var newIndex:Number = changedEvent.newIndex;

visible = checkDisplay(target, newIndex);

}
}

/**
* This function updates the selected view child of the signalling container
* and then compares the path from our IFrame up the displaylist to see if
* the index settings match. Only an exact match all the way down to our
* IFrame will satisfy the condition to display the IFrame contents.
*
* @param target Object event source
* @param newIndex Number index from target object.
*
*/
private function checkDisplay(target:Object, newIndex:Number):Boolean
{
var valid:Boolean = false;

if (target is Container)
{
var container:DisplayObjectContainer = DisplayObjectContainer(target);

// Update current setting
settingDict[container] = newIndex;

valid = true;

for (var item:Object in containerDict)
{
var index:Number = lookupIndex(item as Container);
var setting:Number = lookupSetting(item as Container);

valid = valid&&(index==setting);
}

}

return valid;
}

/**
* Return index of child item on path down to this object. If not
* found then return -1;
*
* @param target Container object
*
*/
public function lookupIndex(target:Container):Number
{
var index:Number = -1;

try
{
index = containerDict[target];
}
catch (e:Error)
{
// Error not found, we have to catch this or a silent exception
// will be thrown.
trace(e);
}

return index;
}

/**
* Return index of child item on path down to this object. If not
* found then return -1;
*
* @param target Container object
*
*/
public function lookupSetting(target:Container):Number
{
var index:Number = -1;

try
{
index = settingDict[target];
}
catch (e:Error)
{
// Error not found, we have to catch this or a silent exception
// will be thrown.
trace(e);
}

return index;
}

/**
* Adjust frame position to match the exposed area in the application.
*
*/
private function moveIFrame(): void
{

var localPt:Point = new Point(0, 0);
var globalPt:Point = this.localToGlobal(localPt);

ExternalInterface.call(“moveIFrame”, frameId, iframeId, globalPt.x, globalPt.y, this.width, this.height);
}

/**
* Triggered by change to component properties.
*
*/
override protected function commitProperties():void
{
super.commitProperties();

if (source)
{
ExternalInterface.call(“loadIFrame”, frameId, iframeId, source);

// Trigger re-layout of iframe contents.
invalidateDisplayList();
}
}

/**
* Triggered when display contents change. Adjusts frame layout.
*
* @param unscaledWidth
* @param unscaledHeight
*
*/
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);

moveIFrame();
}

/**
* Set source url
*
* @param url Frame contents
*
*/
public function set source(source: String): void
{
if (source)
{
__source = source;

invalidateProperties();
}
}

/**
* Return url of frame contents
*
*/
public function get source(): String
{
return __source;
}

/**
* Sets visibility of html iframe. Rtn calls inserted javascript functions.
*
* @param visible Boolean flag
*
*/
override public function set visible(visible: Boolean): void
{
super.visible=visible;

if (visible)
{
ExternalInterface.call(“showIFrame”, frameId);
}
else
{
ExternalInterface.call(“hideIFrame”, frameId);
}

}

}

}

—–Inline Attachment Follows—–

<?xml version=”1.0″ encoding=”utf-8″?>

<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml
xmlns:local=”*”
creationComplete=”init();”
viewSourceURL=”srcview/index.html”>

<mx:Script>
<![CDATA[
private function init():void
{
iFrame.visible=true;
}
]]>
</mx:Script>
<mx:HBox width=”100%” height=”100%”>

<mx:Panel title=”Tree” width=”200″ height=”100%” roundedBottomCorners=”true”>
<mx:Tree id=”tree” width=”100%” height=”100%” dataProvider=”{treeData}”
labelField=”@label” showRoot=”false”
change=”iFrame.source = (Tree(event.target).selectedItem.attribute(‘path’).toString());” />
</mx:Panel>

<mx:Panel width=”100%” height=”100%” title=”Content” paddingTop=”1″ paddingBottom=”1″ paddingLeft=”1″ paddingRight=”1″ >
<local:IFrame id=”iFrame” source=”http://www.adobe.com/devnet/flex/” width=”100%” height=”100%”/>
<mx:ControlBar>
<mx:CheckBox id=”cbVisible” label=”IFrame Visible” selected=”true” click=”iFrame.visible=cbVisible.selected”/>
</mx:ControlBar>
</mx:Panel>

</mx:HBox>

<mx:XMLList id=”treeData”>
<node label=”Flex Resources”>
<node label=”Flex Developer Center” path=”http://www.adobe.com/devnet/flex/” />
<node label=”Open ppt file ” path=”/TNOU/jsp/MKU.ppt” />
<node label=”Open xls file ” path=”/TNOU/jsp/list.xls” />
<node label=”Open doc file ” path=”/TNOU/jsp/PURA.doc” />
<node label=”OpenOffice WordFile” path=”/TNOU/jsp/ig1.rtf”/>
<node label=”OpenOffice PPTFile” path=”/TNOU/jsp/sxwFileDemo.sxw”/>

<!– these sites pop themselves out of a frame:
<node label=”flex.org” path=”http://www.flex.org” />
<node label=”Adobe Labs” path=”http://labs.adobe.com/wiki/index.php/Main_Page” />
–>
</node>
<node label=”Search”>
<node label=”Google” path=”http://www.google.com” />
<node label=”Yahoo” path=”/TNOU/jsp/Rich_Internet_Applications_With_Adobe_Flex_and_Java.pdf” />
</node>
</mx:XMLList>

</mx:Application>

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: