Flex IFrame – Web browser in flash (update)

Clipboard02

You can not have a web browser inside your web flash applications right? Well, you can! This solution uses html iframe to generate fake build in browser. So the behaviour of the browser in flash is the same as the one you are previewing this flash in (it is the same one). The best part of it is, you can manipulate with the position and size of this browser directly from flash. sk.yoz.html.IFrame solution was inspired by Alistair Rutherford, www.netthreads.co.uk.

Flex Iframe application

Core of this thing is sk.yoz.html.IFrame class. It extends Canvas that is used to inherit properties and methods for positioning and sizing. There is one in order to make it work – every IFrame element must have id!

package sk.yoz.html
{
    import flash.events.Event;
    import flash.external.ExternalInterface;
    import flash.geom.Point;

    import mx.containers.Canvas;

    public class IFrame extends Canvas
    {
        public var methodResize:String = "FlexIFrame.resize";
        public var methodMove:String = "FlexIFrame.move";
        public var methodNavigate:String = "FlexIFrame.navigate";
        public var methodVisibility:String = "FlexIFrame.visibility";

        public var positionChanged:Boolean = false;
        public var sizeChanged:Boolean = false;

        private var _autoResize:Boolean = false;
        private var _url:String = '';

        public function IFrame()
        {
            super();
            addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler)
        }

        override public function set id(value:String):void
        {
            super.id = value;
        }

        protected function addedToStageHandler(event:Event):void
        {
            positionChanged = true;
            sizeChanged = true;
            invalidateProperties();
        }

        public function set autoResize(value:Boolean):void
        {
            _autoResize = value;
            if(value)
                addEventListener(Event.RESIZE, autoResizeHandler);
            else
                removeEventListener(Event.RESIZE, autoResizeHandler);
        }

        public function get autoResize():Boolean
        {
            return _autoResize;
        }

        protected function autoResizeHandler(event:Event):void
        {
            positionChanged = true;
            sizeChanged = true;
            invalidateProperties();
        }

        override protected function commitProperties():void
        {
            super.commitProperties();

            if(positionChanged)
            {
                var point:Point = localToGlobal(new Point(0, 0));
                callJS(methodMove, point.x, point.y);
                positionChanged = false;
            }

            if(sizeChanged)
            {
                callJS(methodResize, width, height);
                sizeChanged = false;
            }
        }

        public function set url(value:String):void
        {
            _url = value;
            callJS(methodNavigate, value)
        }

        public function get url():String
        {
            return _url;
        }

        protected function callJS(method:String, ... values):void
        {
            if(!id)
                throw new Error("IFrame id is not defined");
            var args:Array = [method, id];
            try
            {
                ExternalInterface.call.apply(ExternalInterface, args.concat(values));
            }
            catch(error:Error)
            {
                trace(error.message);
            }
        }

        override public function set visible(value:Boolean):void
        {
            super.visible = value;
            callJS(methodVisibility, value);
        }

        override public function set width(value:Number):void
        {
            super.width = value;
            callJS(methodResize, value, height);
        }

        override public function set height(value:Number):void
        {
            super.height = value;
            callJS(methodResize, width, value);
        }

        override public function set x(value:Number):void
        {
            super.x = value;
            var point:Point = localToGlobal(new Point(0, 0));
            callJS(methodMove, point.x, point.y);
        }

        override public function set y(value:Number):void
        {
            super.y = value;
            var point:Point = localToGlobal(new Point(0, 0));
            callJS(methodMove, point.x, point.y);
        }
    }
}

FlexIFrame.js is JavaScript file. It uses your flex IFrame id from to create (html iframe) or use html element (any element) with the same id (id in flash = id in html). So you can use your prefabricated html elements (banners etc).

var FlexIFrame = {
    get: function(id)
    {
        var iframe = document.getElementById(id);
        if(!iframe)
            return FlexIFrame.create(id);
        return iframe;
    },

    create: function(id)
    {
        var iframe = document.createElement('iframe');
        iframe.id = id;
        iframe.frameborder = 0;
        iframe.style.position = "absolute";
        iframe.style.zIndex = 1;
        iframe.style.border = "none";
        document.body.insertBefore(iframe, document.body.firstChild);
        return iframe;
    },

    resize: function(id, width, height)
    {
        var iframe = FlexIFrame.get(id);
        iframe.style.width = width + "px";
        iframe.style.height = height + "px";
    },

    move: function(id, x, y)
    {
        var iframe = FlexIFrame.get(id);
        iframe.style.left = x + "px";
        iframe.style.top = y + "px";
    },

    navigate: function(id, url)
    {
        var iframe = FlexIFrame.get(id);
        iframe.src = url;
    },

    visibility: function(id, visible)
    {
        var iframe = FlexIFrame.get(id);
        iframe.style.display = visible ? "block" : "none";
    }
}

This is simple applicationion presenting draggable TitleWindow with “web browser” inside:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()" xmlns:html="sk.yoz.html.*">
<mx:Script>
<![CDATA[
    private function init():void
    {
        go();
    }

    private function go():void
    {
        iframe.url = iframeURL.text;
    }

    private function mouseDownHandler():void
    {
        container.startDrag();
        container.addEventListener(Event.ENTER_FRAME, enterFrameDrag);
    }

    private function mouseUpHandler():void
    {
        container.stopDrag();
    }

    private function enterFrameDrag(event:Event):void
    {
        iframe.positionChanged = true;
        iframe.invalidateProperties();
    }
]]>
</mx:Script>
<mx:TitleWindow id="container" layout="vertical" width="300" height="300"
    mouseDown="mouseDownHandler()" mouseUp="mouseUpHandler()" >
    <mx:HBox width="100%">
        <mx:TextInput id="iframeURL" text="http://blog.yoz.sk" width="100%"
            enter="go()"/>
        <mx:Button label="Go" click="go()"/>
    </mx:HBox>
    <html:IFrame width="100%" height="100%" id="iframe" autoResize="true"/>
</mx:TitleWindow>
</mx:Application>

Finally do not forget to add flexiframe.js into your .html file:

<html>
    <head>
        <script type="text/javascript" src="js/flexiframe.js"></script>
        ...

Update (Feb 8, 2010): flexiframe.js resize() method uses style property for width and height (instead of original html element width, height)

9 comments so far

  1. Polprav November 3, 2009 02:30

    Hello from Russia!
    Can I quote a post “No teme” in your blog with the link to you?

  2. Jozef Chúťka November 3, 2009 10:27

    sure

  3. [...] post connects my 3 previous posts: Flex IFrame – Web browser in flash, FacebookLogger and Facebook Extended Permissions With Authorization by Overriding Class in swc in [...]

  4. [...] import flexiframe.js used for positioning html input on correct [...]

  5. Pedro Varela March 16, 2010 21:59

    Hey Jozef.. yeap you are right! we can have HTML on our flash apps.. but the IFrame is the wors’t thing we can have in a Flex app, why? Because all PopUps will remain behind the IFrame, you have to implement workarounds like hiding the IFrame if a PopUp has to show, other little terrible thing, is that you have to relocate the IFrame if your browser is resize.

    That’s why I’m against the IFrame.. so for everybody who reads this, if you don´t really have to render HTML in your app, don´t do it.

  6. Jozef Chúťka March 17, 2010 00:12

    Hi Pedro, thanks for your comment. I think you misunderstood the whole example and aim of this Class. It does not mean that all your PopUps are gonna be raplaced by HTML iframe. HTML iframe only overlaps the sk.yoz.html.IFrame class! Its aim IS to show iframe positioned and sized over this element. There is no workaround needed for hidding etc. You can hide it using IFrame.visible = false. Yes, you are right that in specific case (when your flash app extends with browser resize), you need to call:
    iframe.positionChanged = true;
    iframe.sizeChanged = true;
    iframe.invalidateProperties();
    it is meant to be used that way

    whats more, sk.yoz.html.IFrame, can be used for positioning any other html element, see some examples here:
    http://blog.yoz.sk/2010/02/textinput-wmode-opaque-transparent-workaround/
    http://blog.yoz.sk/2010/01/elegant-facebook-login-for-desktop-application/

  7. bar June 9, 2010 04:02

    hi..
    im trying to do this a lot of time in my websites,
    you can download rar file that include all works?

    thanks

  8. Jozef Chúťka June 9, 2010 09:37

    @bar just copy paste content of these 3 files + add .js line into your main html wrapper thats all

  9. Rafael SP August 11, 2010 23:57

    It works!

    Thank you for this post. It helped me a lot.

Leave a comment

Please be polite and on topic. Your e-mail will never be published.

Get Adobe Flash playerPlugin by wpburn.com wordpress themes