Hi all,
I place instances of iframe component (the Alistair Rutherford's
version of the C. Conraets's component) ) into a tabnavigator itself
into a panel
It works nearly perfectly (thx to Alistair's help) but as you can
check by yourself, after some moves mixed with some tab switching, It
fails to refresh the iframe area ( say containers located to the
right whereas iframe content stay at the left !!?!!) I can't even
determine after which sequence it appears but it always appears after
somes clicks...)
It sounds that some event handlings are still missing but I have no
idea which ones..
Your help would really be helpful.
Thx!
Eric
( mxml file is below and iFrame.as is attached if you want to give a try)
_______________________________________________________________________________________
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:local="*"
layout="absolute" viewSourceURL="srcview/index.html"
creationComplete="init()">
<mx:states>
<mx:State name="moved">
<mx:SetProperty target="{panel1}" name="x" value="0"/>
<mx:SetProperty target="{panel1}" name="height"
value="400"/>
</mx:State>
</mx:states>
<mx:Script>
<![CDATA[
import mx.events.TweenEvent;
import mx.events.EffectEvent;
import mx.events.IndexChangedEvent;
private function init():void{
myMove.addEventListener(TweenEvent.TWEEN_START,
onSlide);
myMove.addEventListener(TweenEvent.TWEEN_UPDATE, onSlide);
myMove.addEventListener(TweenEvent.TWEEN_END,
onSlide);
}
private function onSlide(evt:Event):void{
var frame1:IFrame = IFrame(tab1.selectedChild);
frame1.invalidateDisplayList();
}
]]>
</mx:Script>
<mx:Panel id="panel1" width="344" height="400" y="80" x="600">
<mx:TabNavigator id="tab1"
width="100%" height="100%"
x="10" y="40">
<local:IFrame id="url1" label="Google"
source="http://www.google.com"
width="100%" height="100%"
/>
<local:IFrame id="url2" label="Yahoo"
source="http://www.yahoo.com"
width="100%" height="100%" />
</mx:TabNavigator>
</mx:Panel>
<mx:Button x="240" y="10" label="Move To Right"
click="currentState=''"/>
<mx:Button x="127" y="10" label="Move To Left"
click="currentState='moved'"/>
<mx:transitions>
<mx:Transition id="myTransition" fromState="*" toState="*">
<mx:Move id="myMove" target="{panel1}"
duration="400"/>
</mx:Transition>
</mx:transitions>
</mx:Application>
// -----------------------------------------------------------------------
// IFrame.as - Alistair Rutherford, 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
// 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);
}
}
}
}