    /*!
     * Ext JS Library 4.0
     * Copyright(c) 2006-2011 Sencha Inc.
     * licensing@sencha.com
     * http://www.sencha.com/license
     */

    /**
     * Barebones iframe implementation. For serious iframe work, see the
     * ManagedIFrame extension
     * (http://www.sencha.com/forum/showthread.php?71961).
     */
    Ext.define('Ext.ux.IFrame', {
        extend: 'Ext.Component',

        alias: 'widget.uxiframe',

        loadMask: 'Loading...',

        src: 'about:blank',

        renderTpl: [
            '<iframe src="{src}" name="{frameName}" width="100%" height="100%" frameborder="0"></iframe>'
        ],

        initComponent: function () {
            this.callParent();

            this.frameName = this.frameName || this.id + '-frame';

            this.addEvents(
                'beforeload',
                'load'
            );

            Ext.apply(this.renderSelectors, {
                iframeEl: 'iframe'
            });
        },

        initEvents : function() {
            var me = this;
            me.callParent();
            me.iframeEl.on('load', me.onLoad, me);
        },

        initRenderData: function() {
            return Ext.apply(this.callParent(), {
                src: this.src,
                frameName: this.frameName
            });
        },

        getBody: function() {
            var doc = this.getDoc();
            return doc.body || doc.documentElement;
        },

        getDoc: function() {
            try {
                return this.getWin().document;
            } catch (ex) {
                return null;
            }
        },

        getWin: function() {
            var me = this,
                name = me.frameName,
                win = Ext.isIE
                    ? me.iframeEl.dom.contentWindow
                    : window.frames[name];
            return win;
        },

        getFrame: function() {
            var me = this;
            return me.iframeEl.dom;
        },

        beforeDestroy: function () {
            this.cleanupListeners(true);
            this.callParent();
        },

        cleanupListeners: function(destroying){
            var doc, prop;

            if (this.rendered) {
                try {
                    doc = this.getDoc();
                    if (doc) {
                        Ext.EventManager.removeAll(doc);
                        if (destroying) {
                            for (prop in doc) {
                                if (doc.hasOwnProperty && doc.hasOwnProperty(prop)) {
                                    delete doc[prop];
                                }
                            }
                        }
                    }
                } catch(e) { }
            }
        },

        onLoad: function() {
            var me = this,
                doc = me.getDoc(),
                fn = me.onRelayedEvent;

            if (doc) {
                try {
                    Ext.EventManager.removeAll(doc);

                    // These events need to be relayed from the inner document (where they stop
                    // bubbling) up to the outer document. This has to be done at the DOM level so
                    // the event reaches listeners on elements like the document body. The effected
                    // mechanisms that depend on this bubbling behavior are listed to the right
                    // of the event.
                    Ext.EventManager.on(doc, {
                        mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
                        mousemove: fn, // window resize drag detection
                        mouseup: fn,   // window resize termination
                        click: fn,     // not sure, but just to be safe
                        dblclick: fn,  // not sure again
                        scope: me
                    });
                } catch(e) {
                    // cannot do this xss
                }

                // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
                Ext.EventManager.on(this.getWin(), 'beforeunload', me.cleanupListeners, me);

                this.el.unmask();
                this.fireEvent('load', this);

            } else if(me.src && me.src != '') {

                this.el.unmask();
                this.fireEvent('error', this);
            }

        },

        onRelayedEvent: function (event) {
            // relay event from the iframe's document to the document that owns the iframe...

            var iframeEl = this.iframeEl,

                // Get the left-based iframe position
                iframeXY = Ext.Element.getTrueXY(iframeEl),
                originalEventXY = event.getXY(),

                // Get the left-based XY position.
                // This is because the consumer of the injected event (Ext.EventManager) will
                // perform its own RTL normalization.
                eventXY = Ext.EventManager.getPageXY(event.browserEvent);

            // the event from the inner document has XY relative to that document's origin,
            // so adjust it to use the origin of the iframe in the outer document:
            event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];

            event.injectEvent(iframeEl); // blame the iframe for the event...

            event.xy = originalEventXY; // restore the original XY (just for safety)
        },

        load: function (src) {
            var me = this,
                text = me.loadMask,
                frame = me.getFrame();

            if (me.fireEvent('beforeload', me, src) !== false) {
                if (text && me.el) {
                    me.el.mask(text);
                }

                frame.src = me.src = (src || me.src);
            }
        }
    });