/**
 * Given a component hierarchy of this:
 *
 *      {
 *          xtype: 'panel',
 *          id: 'ContainerA',
 *          layout: 'hbox',
 *          renderTo: Ext.getBody(),
 *          items: [
 *              {
 *                  id: 'ContainerB',
 *                  xtype: 'container',
 *                  items: [
 *                      { id: 'ComponentA' }
 *                  ]
 *              }
 *          ]
 *      }
 *
 * The rendering of the above proceeds roughly like this:
 *
 *  - ContainerA's initComponent calls #render passing the `renderTo` property as the
 *    container argument.
 *  - `render` calls the `getRenderTree` method to get a complete {@link Ext.dom.Helper} spec.
 *  - `getRenderTree` fires the "beforerender" event and calls the #beforeRender
 *    method. Its result is obtained by calling #getElConfig.
 *  - The #getElConfig method uses the `renderTpl` and its render data as the content
 *    of the `autoEl` described element.
 *  - The result of `getRenderTree` is passed to {@link Ext.dom.Helper#append}.
 *  - The `renderTpl` contains calls to render things like docked items, container items
 *    and raw markup (such as the `html` or `tpl` config properties). These calls are to
 *    methods added to the {@link Ext.XTemplate} instance by #setupRenderTpl.
 *  - The #setupRenderTpl method adds methods such as `renderItems`, `renderContent`, etc.
 *    to the template. These are directed to "doRenderItems", "doRenderContent" etc..
 *  - The #setupRenderTpl calls traverse from components to their {@link Ext.layout.Layout}
 *    object.
 *  - When a container is rendered, it also has a `renderTpl`. This is processed when the
 *    `renderContainer` method is called in the component's `renderTpl`. This call goes to
 *    Ext.layout.container.Container#doRenderContainer. This method repeats this
 *    process for all components in the container.
 *  - After the top-most component's markup is generated and placed in to the DOM, the next
 *    step is to link elements to their components and finish calling the component methods
 *    `onRender` and `afterRender` as well as fire the corresponding events.
 *  - The first step in this is to call #finishRender. This method descends the
 *    component hierarchy and calls `onRender` and fires the `render` event. These calls
 *    are delivered top-down to approximate the timing of these calls/events from previous
 *    versions.
 *  - During the pass, the component's `el` is set. Likewise, the `renderSelectors` and
 *    `childEls` are applied to capture references to the component's elements.
 *  - These calls are also made on the {@link Ext.layout.container.Container} layout to
 *    capture its elements. Both of these classes use {@link Ext.util.ElementContainer} to
 *    handle `childEls` processing.
 *
 * @private
 */
Ext.define('Ext.util.Renderable', {
    mixinId: 'renderable',
 
    requires: [
        'Ext.dom.Element'
    ],
 
    frameIdRegex: /[-]frame\d+[TMB][LCR]$/,
    frameCls: Ext.baseCSSPrefix + 'frame',
    frameElNames: ['TL', 'TC', 'TR', 'ML', 'MC', 'MR', 'BL', 'BC', 'BR', 'Table'],
 
    /* eslint-disable indent, max-len */
    frameTpl: [
        '<tpl if="hasTabGuard">{% this.renderTabGuard(out, values, \'before\'); %}</tpl>',
        '<tpl if="top">',
            '<tpl if="left"><div id="{fgid}TL" data-ref="frameTL" class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl>{frameElCls}" role="presentation"></tpl>',
                '<tpl if="right"><div id="{fgid}TR" data-ref="frameTR" class="{frameCls}-tr {baseCls}-tr {baseCls}-{ui}-tr<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl>{frameElCls}" role="presentation"></tpl>',
                    '<div id="{fgid}TC" data-ref="frameTC" class="{frameCls}-tc {baseCls}-tc {baseCls}-{ui}-tc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl>{frameElCls}" role="presentation"></div>',
                '<tpl if="right"></div></tpl>',
            '<tpl if="left"></div></tpl>',
        '</tpl>',
        '<tpl if="left"><div id="{fgid}ML" data-ref="frameML" class="{frameCls}-ml {baseCls}-ml {baseCls}-{ui}-ml<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl>{frameElCls}" role="presentation"></tpl>',
            '<tpl if="right"><div id="{fgid}MR" data-ref="frameMR" class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl>{frameElCls}" role="presentation"></tpl>',
                '<div id="{fgid}Body" data-ref="frameBody" class="{frameBodyCls} {frameCls}-mc {baseCls}-mc {baseCls}-{ui}-mc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl>{frameElCls}" role="presentation">',
                    '{%this.applyRenderTpl(out, values)%}',
                '</div>',
            '<tpl if="right"></div></tpl>',
        '<tpl if="left"></div></tpl>',
        '<tpl if="bottom">',
            '<tpl if="left"><div id="{fgid}BL" data-ref="frameBL" class="{frameCls}-bl {baseCls}-bl {baseCls}-{ui}-bl<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl>{frameElCls}" role="presentation"></tpl>',
                '<tpl if="right"><div id="{fgid}BR" data-ref="frameBR" class="{frameCls}-br {baseCls}-br {baseCls}-{ui}-br<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl>{frameElCls}" role="presentation"></tpl>',
                    '<div id="{fgid}BC" data-ref="frameBC" class="{frameCls}-bc {baseCls}-bc {baseCls}-{ui}-bc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl>{frameElCls}" role="presentation"></div>',
                '<tpl if="right"></div></tpl>',
            '<tpl if="left"></div></tpl>',
        '</tpl>',
        '<tpl if="hasTabGuard">{% this.renderTabGuard(out, values, \'after\'); %}</tpl>'
    ],
 
    frameTableTpl: [
        '<tpl if="hasTabGuard">{% this.renderTabGuard(out, values, \'before\'); %}</tpl>',
        '<table id="{fgid}Table" data-ref="frameTable" class="{frameCls} ', Ext.baseCSSPrefix + 'table-plain" cellpadding="0" role="presentation">',
            '<tpl if="top">',
                '<tr role="presentation">',
                    '<tpl if="left"><td id="{fgid}TL" data-ref="frameTL" class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl>{frameElCls}" role="presentation"></td></tpl>',
                    '<td id="{fgid}TC" data-ref="frameTC" class="{frameCls}-tc {baseCls}-tc {baseCls}-{ui}-tc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl>{frameElCls}" role="presentation"></td>',
                    '<tpl if="right"><td id="{fgid}TR" data-ref="frameTR" class="{frameCls}-tr {baseCls}-tr {baseCls}-{ui}-tr<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl>{frameElCls}" role="presentation"></td></tpl>',
                '</tr>',
            '</tpl>',
            '<tr role="presentation">',
                '<tpl if="left"><td id="{fgid}ML" data-ref="frameML" class="{frameCls}-ml {baseCls}-ml {baseCls}-{ui}-ml<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl>{frameElCls}" role="presentation"></td></tpl>',
                '<td id="{fgid}Body" data-ref="frameBody" class="{frameBodyCls} {frameCls}-mc {baseCls}-mc {baseCls}-{ui}-mc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl>{frameElCls}" style="{mcStyle}" role="presentation">',
                    '{%this.applyRenderTpl(out, values)%}',
                '</td>',
                '<tpl if="right"><td id="{fgid}MR" data-ref="frameMR" class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl>{frameElCls}" role="presentation"></td></tpl>',
            '</tr>',
            '<tpl if="bottom">',
                '<tr role="presentation">',
                    '<tpl if="left"><td id="{fgid}BL" data-ref="frameBL" class="{frameCls}-bl {baseCls}-bl {baseCls}-{ui}-bl<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl>{frameElCls}" role="presentation"></td></tpl>',
                    '<td id="{fgid}BC" data-ref="frameBC" class="{frameCls}-bc {baseCls}-bc {baseCls}-{ui}-bc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl>{frameElCls}" role="presentation"></td>',
                    '<tpl if="right"><td id="{fgid}BR" data-ref="frameBR" class="{frameCls}-br {baseCls}-br {baseCls}-{ui}-br<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl>{frameElCls}" role="presentation"></td></tpl>',
                '</tr>',
            '</tpl>',
        '</table>',
        '<tpl if="hasTabGuard">{% this.renderTabGuard(out, values, \'after\'); %}</tpl>'
    ],
    /* eslint-enable indent, max-len */
 
    /**
     * @property {Number} _renderState
     * This property holds one of the following values during the render process:
     *
     *   * **0** - The component is not rendered.
     *   * **1** - The component has fired beforerender and is about to call beforeRender.
     *    The component has just started rendering.
     *   * **2** - The component has finished the `beforeRender` process and is about to
     *    call `onRender`. This is when `rendering` is set to `true`.
     *   * **3** - The component has started `onRender`. This is when `rendered` is set
     *    to `true`.
     *   * **4** - The component has finished its afterrender process.
     *
     * @private
     * @readonly
     * @since 5.0.0
     */
    _renderState: 0,
 
    _layerCls: Ext.baseCSSPrefix + 'layer',
    _fixedLayerCls: Ext.baseCSSPrefix + 'fixed-layer',
 
    // Some components will have such roles that do not actively participate
    // in user interaction, and thus do not need their ARIA attributes updated
    ariaStaticRoles: {
        presentation: true,
        article: true,
        definition: true,
        directory: true,
        document: true,
        img: true,
        heading: true,
        math: true,
        note: true,
        banner: true,
        complementary: true,
        contentinfo: true,
        navigation: true,
        search: true,
 
        // When a role is not defined it is akin to static
        'undefined': true,
        'null': true
    },
 
    statics: {
        makeRenderSetter: function(cfg, renderState) {
            var name = cfg.name;
 
            return function(value) {
                var me = this,
                    bucket = (me.renderConfigs || (me.renderConfigs = {})),
                    pending = bucket[renderState];
 
                if (me._renderState >= renderState) {
                    (cfg.setter || cfg.getSetter()).call(me, value);
                }
                else {
                    if (!pending) {
                        bucket[renderState] = pending = {};
                    }
 
                    if (!(name in pending)) {
                        pending[name] = me[name];
                    }
 
                    me[name] = value;
                }
 
                return me;
            };
        },
 
        processRenderConfig: function(source, configName, state) {
            // Even though this is not inheritableState, our onClassExtended adds it to
            // all derived classes so that our "this" pointer is the derived class.
            var proto = this.prototype,
                configurator = this.getConfigurator(),
                Renderable = Ext.util.Renderable,
                makeSetter = Renderable.makeRenderSetter,
                renderConfig = source[configName],
                cachedSetter, cfg, name, setterName;
 
            for (name in renderConfig) {
                cfg = Ext.Config.get(name);
 
                if (!proto[setterName = cfg.names.set]) {
                    cachedSetter = (cfg.renderSetter || (cfg.renderSetter = {}));
                    proto[setterName] = cachedSetter[state] ||
                                        (cachedSetter[state] = makeSetter(cfg, state));
                }
            }
 
            delete source[configName];
            configurator.add(renderConfig);
        }
    },
 
    onClassMixedIn: function(targetClass) {
        var override = targetClass.override,
            processRenderConfig = this.processRenderConfig,
            processOverride = function(body) {
                if (body.beforeRenderConfig) {
                    this.processRenderConfig(body, 'beforeRenderConfig', 1);
                }
 
                if (body.renderConfig) {
                    this.processRenderConfig(body, 'renderConfig', 3);
                }
 
                override.call(this, body);
            },
            processClass = function(theClass, classBody) {
                // We need to process overrides for renderConfig declarations:
                theClass.override = processOverride;
 
                // While we are here we add this method (an inheritableStatic basically)
                theClass.processRenderConfig = processRenderConfig;
 
                if (classBody.beforeRenderConfig) {
                    theClass.processRenderConfig(classBody, 'beforeRenderConfig', 1);
                }
 
                if (classBody.renderConfig) {
                    theClass.processRenderConfig(classBody, 'renderConfig', 3);
                }
            };
 
        // Process Component itself.
        processClass(targetClass, targetClass.prototype);
 
        // And apply to all Component-derived classes as well:
        targetClass.onExtended(processClass);
    },
 
    /**
     * Allows additional behavior after rendering is complete. At this stage, the 
     * {@link Ext.Component Component's} {@link Ext.Component#getEl Element} will have 
     * been styled according to the configuration, will have had any configured CSS 
     * class names added, and will be in the configured visibility and configured enable 
     * state.
     * 
     * **Note:** If the Component has a {@link Ext.Component#controller ViewController} 
     * and the controller has an {@link Ext.app.ViewController#afterRender afterRender} 
     * method it will be called passing the Component as the single param.
     *
     * @template
     * @protected
     */
    afterRender: function() {
        var me = this,
            data = {},
            protoEl = me.protoEl,
            target = me.el,
            controller, item, pre, hidden, contentEl;
 
        me.finishRenderChildren();
        me._renderState = 4;
 
        // We need to do the contentEl here because it depends on the layout items (inner/outerCt)
        // to be rendered before we can put it in
        if (me.contentEl) {
            pre = Ext.baseCSSPrefix;
            hidden = pre + 'hidden-';
            contentEl = me.contentEl = Ext.get(me.contentEl);
            contentEl.component = me;
            contentEl.removeCls([ pre + 'hidden', hidden + 'display', hidden + 'offsets' ]);
            me.getContentTarget().appendChild(contentEl.dom);
        }
 
        protoEl.writeTo(data);
 
        // Here we apply any styles that were set on the protoEl during the rendering phase
        // A majority of times this will not happen, but we still need to handle it
 
        item = data.removed;
 
        if (item) {
            target.removeCls(item);
        }
 
        item = data.cls;
 
        if (item.length) {
            target.addCls(item);
        }
 
        item = data.style;
 
        if (data.style) {
            target.setStyle(item);
        }
 
        me.protoEl = null;
 
        // If this is the outermost Container, lay it out as soon as it is rendered.
        // Some Components like Ext.LoadMask will lay out themselves and some like
        // Ext.dd.StatusProxy will even render themselves to a detached document body,
        // so we allow them to opt out of the Ext layouts.
        if (!me.ownerCt && !me.skipLayout) {
            me.updateLayout();
        }
 
        if (!(me.x && me.y) && (me.pageX || me.pageY)) {
            me.setPagePosition(me.pageX, me.pageY);
        }
 
        if (me.disableOnRender) {
            me.onDisable();
        }
 
        controller = me.controller;
 
        if (controller && controller.afterRender) {
            controller.afterRender(me);
        }
 
        if (me.focusableContainer && me.initFocusableContainer) {
            me.initFocusableContainer();
        }
    },
 
    afterFirstLayout: function(width, height) {
        var me = this,
            x = me.x,
            y = me.y,
            alignSpec = me.defaultAlign,
            alignOffset = me.alignOffset,
            controller, hasX, hasY, pos, xy;
 
        // We only have to set absolute position here if there is no ownerlayout
        // which should take responsibility. Consider the example of rendered components
        // outside of a viewport - these might need their positions setting.
        if (!me.ownerLayout) {
            hasX = x !== undefined;
            hasY = y !== undefined;
        }
 
        // For floaters, calculate x and y if they aren't defined by aligning
        // the sized element to the center of either the container or the ownerCt
        if (me.floating && !me.preventDefaultAlign && (!hasX || !hasY)) {
            if (me.floatParent) {
                pos = me.floatParent.getTargetEl().getViewRegion();
 
                xy = me.el.getAlignToXY(
                    me.alignTarget || me.floatParent.getTargetEl(), alignSpec, alignOffset
                );
 
                pos.x = xy[0] - pos.x;
                pos.y = xy[1] - pos.y;
            }
            else {
                xy = me.el.getAlignToXY(me.alignTarget || me.container, alignSpec, alignOffset);
                pos = me.el.translateXY(xy[0], xy[1]);
            }
 
            x = hasX ? x : pos.x;
            y = hasY ? y : pos.y;
            hasX = hasY = true;
        }
 
        if (hasX || hasY) {
            me.setPosition(x, y);
        }
 
        me.onBoxReady(width, height);
 
        controller = me.controller;
 
        if (controller && controller.boxReady) {
            controller.boxReady(me, width, height);
        }
    },
 
    /**
     * Allows additional behavior before rendering.
     * 
     * **Note:** If the Component has a {@link Ext.Component#controller ViewController} 
     * and the controller has a {@link Ext.app.ViewController#beforeRender beforeRender} 
     * method it will be called passing the Component as the single param.
     *
     * @template
     * @protected
     */
    beforeRender: function() {
        var me = this,
            floating = me.floating,
            layout = me.getComponentLayout(),
            cls = me.userCls,
            controller;
 
        me._renderState = 1;
 
        me.ariaUsesMainElement = me.ariaEl === 'el';
 
        controller = me.controller;
 
        if (controller && controller.beforeRender) {
            controller.beforeRender(me);
        }
 
        // Force bindings to be created
        me.initBindable();
 
        if (me.renderConfigs) {
            me.flushRenderConfigs();
        }
 
        if (cls) {
            me.addCls(cls);
        }
 
        if (floating) {
            me.addCls(me.fixed ? me._fixedLayerCls : me._layerCls);
 
            cls = floating.cls;
 
            if (cls) {
                me.addCls(cls);
            }
        }
 
        // Just before rendering, set the frame flag if we are an always-framed component
        // like Window or Tip.
        me.frame = me.frame || me.alwaysFramed;
 
        if (!layout.initialized) {
            layout.initLayout();
        }
 
        // Attempt to set overflow style prior to render if the targetEl can be accessed.
        // If the targetEl does not exist yet, this will take place in finishRender
        me.initOverflow();
 
        me.setUI(me.ui);
    },
 
    /**
     * @private
     * Called from the selected frame generation template to insert this Component's inner structure
     * inside the framing structure.
     *
     * When framing is used, a selected frame generation template is used as the primary template
     * of the #getElConfig instead of the configured {@link Ext.Component#renderTpl renderTpl}.
     * The renderTpl is invoked by this method which is injected into the framing template.
     */
    doApplyRenderTpl: function(out, values) {
        // Careful! This method is bolted on to the frameTpl so all we get for context is
        // the renderData! The "this" pointer is the frameTpl instance!
        var me = values.$comp,
            tpl;
 
        // Don't do this if the component is already rendered:
        if (!me.rendered) {
            tpl = me.initRenderTpl();
            tpl.applyOut(values.renderData, out);
        }
    },
 
    getElConfig: function() {
        var me = this,
            autoEl = me.autoEl,
            frameInfo = me.getFrameInfo(),
            config = {
                tag: 'div',
                tpl: frameInfo ? me.initFramingTpl(frameInfo.table) : me.initRenderTpl()
            },
            layoutTargetCls = me.layoutTargetCls,
            protoEl = me.protoEl,
            ariaRole = me.ariaRole,
            frameData;
 
        me.initStyles(protoEl);
 
        // If we're not framing, then just add to the element, otherwise we need to add
        // it to the frameBody, since it's our targetEl, but we don't have a handle on it yet.
        if (layoutTargetCls && !frameInfo) {
            protoEl.addCls(layoutTargetCls);
        }
 
        protoEl.writeTo(config);
        protoEl.flush();
 
        if (autoEl) {
            if (Ext.isString(autoEl)) {
                config.tag = autoEl;
            }
            else {
                Ext.apply(config, autoEl);
            }
        }
 
        if (ariaRole && me.ariaUsesMainElement) {
            config.role = ariaRole;
 
            if (!me.ariaStaticRoles[ariaRole]) {
                config['aria-hidden'] = !!me.hidden;
                config['aria-disabled'] = !!me.disabled;
 
                // ariaLabelledBy takes precedence
                if (me.ariaLabel && !me.ariaLabelledBy) {
                    config['aria-label'] = me.ariaLabel;
                }
 
                // We don't want to handle collapsibleness in subclasses
                if (me.collapsible) {
                    config['aria-expanded'] = !me.collapsed;
                }
 
                // In some cases we need to force some ARIA attributes
                // to be rendered on the ariaEl upfront, e.g. certain
                // state and decorator attributes. It is not semantically
                // correct to set these in ariaAttributes config, so
                // we're using ariaRenderAttributes instance config
                // when available.
                if (me.ariaRenderAttributes) {
                    Ext.apply(config, me.ariaRenderAttributes);
                }
 
                if (me.config.ariaAttributes) {
                    Ext.apply(config, me.getAriaAttributes());
                }
            }
        }
 
        // It's important to assign the id here as an autoEl.id could have been (wrongly)
        // applied and this would get things out of sync
        config.id = me.id;
 
        if (config.tpl) {
            // Use the framingTpl as the main content creating template.
            // It will call out to this.applyRenderTpl(out, values)
            if (frameInfo) {
                config.tplData = frameData = me.getFrameRenderData();
                frameData.renderData = me.initRenderData();
            }
            else {
                config.tplData = me.initRenderData();
            }
        }
 
        // After we have gathered all rendering information, this is no longer needed.
        me.ariaRenderAttributes = null;
 
        return config;
    },
 
    /**
     * This function takes the position argument passed to onRender and returns a
     * DOM element that you can use in the insertBefore.
     * @param {String/Number/Ext.dom.Element/HTMLElement} position Index, element id
     * or element you want to put this component before.
     * @return {HTMLElement} DOM element that you can use in the insertBefore
     */
    getInsertPosition: function(position) {
        // Convert the position to an element to insert before
        if (position !== undefined) {
            if (Ext.isNumber(position)) {
                position = this.container.dom.childNodes[position];
            }
            else {
                position = Ext.getDom(position);
            }
        }
 
        return position;
    },
 
    getRenderTree: function() {
        var me = this,
            ret = null;
 
        if (!me.hasListeners.beforerender || me.fireEvent('beforerender', me) !== false) {
            me._renderState = 1;
 
            me.beforeRender();
 
            // Flag to let the layout's finishRenderItems and afterFinishRenderItems
            // know which items to process
            me.rendering = true;
            me._renderState = 2;
 
            ret = me.getElConfig();
 
            if (me.el) {
                // Since we are producing a render tree, we produce a "proxy el" that will
                // sit in the rendered DOM precisely where me.el belongs. We replace the
                // proxy el in the finishRender phase.
                ret.id = me.$pid = Ext.id(null, me.el.identifiablePrefix);
            }
 
            // ret['data-cmp'] = me.id;
        }
 
        return ret;
    },
 
    /**
     * Initialized the renderData to be used when rendering the renderTpl.
     * @return {Object} Object with keys and values that are going to be applied to the renderTpl
     * @protected
     */
    initRenderData: function() {
        var me = this,
            ariaRole = me.ariaRole,
            data, ariaAttr;
 
        data = Ext.apply({
            $comp: me,
            id: me.id,
            ui: me.ui,
            uiCls: me.uiCls,
            baseCls: me.baseCls,
            componentCls: me.componentCls,
            frame: me.frame,
            hasTabGuard: !!me.tabGuard,
            scrollerCls: me.scrollerCls,
            childElCls: '', // overridden in RTL
            ariaEl: me.ariaEl
        }, me.renderData);
 
        // This code is similar (in fact, almost identical) to the one in getElConfig;
        // we duplicate it for performance reasons.
        if (ariaRole && !me.ariaUsesMainElement) {
            ariaAttr = {
                role: ariaRole
            };
 
            if (!me.ariaStaticRoles[ariaRole]) {
                ariaAttr['aria-hidden'] = !!me.hidden;
                ariaAttr['aria-disabled'] = !!me.disabled;
 
                // ariaLabelledBy takes precedence
                if (me.ariaLabel && !me.ariaLabelledBy) {
                    ariaAttr['aria-label'] = me.ariaLabel;
                }
 
                // We don't want to handle collapsibleness in subclasses
                if (me.collapsible) {
                    ariaAttr['aria-expanded'] = !me.collapsed;
                }
 
                if (me.ariaRenderAttributes) {
                    Ext.apply(ariaAttr, me.ariaRenderAttributes);
                }
 
                if (me.config.ariaAttributes) {
                    Ext.apply(ariaAttr, me.getAriaAttributes());
                }
            }
 
            data.ariaAttributes = ariaAttr;
        }
 
        return data;
    },
 
    /**
     * Template method called when this Component's DOM structure is created.
     *
     * At this point, this Component's (and all descendants') DOM structure *exists* but it has not
     * been layed out (positioned and sized).
     *
     * Subclasses which override this to gain access to the structure at render time should
     * call the parent class's method before attempting to access any child elements of the
     * Component.
     *
     * @param {Ext.dom.Element} parentNode The parent Element in which this Component's
     * encapsulating element is contained.
     * @param {Number} containerIdx The index within the parent Container's child collection
     * of this Component.
     *
     * @template
     * @protected
     */
    onRender: function(parentNode, containerIdx) {
        var me = this,
            x = me.x,
            y = me.y,
            lastBox = null,
            el = me.el,
            scroller = me.scrollable,
            width, height;
 
        me.applyRenderSelectors();
 
        // Update the scroller very early in first layout so that it has the overflow element
        // before any 'boxready', onResize, or 'resize' code gets to run.
        if (scroller && scroller.isScroller) {
            scroller.setElement(me.getOverflowEl());
 
            // IE browsers don't restore scroll position if the component was scrolled and
            // then hidden and shown again, so we must do it manually.
            // See EXTJS-16233.
            if (Ext.isIE) {
                me.showListenerIE = Ext.on('show', me.onGlobalShow, me, {
                    destroyable: true
                });
            }
        }
 
        // Flag set on getRenderTree to flag to the layout's postprocessing routine that
        // the Component is in the process of being rendered and needs postprocessing.
        me.rendering = null;
 
        me.rendered = true;
        me._renderState = 3;
 
        if (me.renderConfigs) {
            me.flushRenderConfigs();
        }
 
        // We need to remember these to avoid writing them during the initial layout:
        if (!= null) {
            lastBox = { x: x };
        }
 
        if (!= null) {
            (lastBox = lastBox || {}).y = y;
        }
 
        // Framed components need their width/height to apply to the frame, which is
        // best handled in layout at present.
        if (!me.getFrameInfo()) {
            width = me.width;
            height = me.height;
 
            if (typeof width === 'number') {
                lastBox = lastBox || {};
                lastBox.width = width;
            }
 
            if (typeof height === 'number') {
                lastBox = lastBox || {};
                lastBox.height = height;
            }
        }
 
        me.lastBox = el.lastBox = lastBox;
    },
 
    /**
     * Renders the Component into the passed HTML element.
     * 
     * **If you are using a {@link Ext.container.Container Container} object to house this
     * Component, then do not use the render method.**
     *
     * A Container's child Components are rendered by that Container's
     * {@link Ext.container.Container#layout layout} manager when the Container is first rendered.
     *
     * When creating complex UIs, it is important to remember that sizing and positioning
     * of child items is the responsibility of the Container's
     * {@link Ext.container.Container#layout layout} manager. If you expect child items to be sized
     * in response to user interactions, you must configure the Container with a layout manager
     * which creates and manages the type of layout you have in mind.
     *
     * **Omitting the Container's {@link Ext.Container#layout layout} config means that a basic
     * layout manager is used which does nothing but render child components sequentially into the
     * Container. No sizing or positioning will be performed in this situation.**
     *
     * @param {Ext.dom.Element/HTMLElement/String} [container] The element this Component should be
     * rendered into. If it is being created from existing markup, this should be omitted.
     * @param {String/Number} [position] The element ID or DOM node index within the container
     * **before** which this component will be inserted (defaults to appending to the end
     * of the container)
     */
    render: function(container, position) {
        var me = this,
            el = me.el,
            ownerLayout = me.ownerLayout,
            vetoed, tree, nextSibling;
 
        if (el && !el.isElement) {
            me.wrapPrimaryEl(el); // ensure me.el is wrapped
            el = me.el;
        }
 
        if (!me.skipLayout) {
            Ext.suspendLayouts();
        }
 
        container = me.initContainer(container);
 
        nextSibling = me.getInsertPosition(position);
 
        if (!el) {
            tree = me.getRenderTree();  // calls beforeRender
 
            if (ownerLayout && ownerLayout.transformItemRenderTree) {
                tree = ownerLayout.transformItemRenderTree(tree);
            }
 
            // tree will be null if a beforerender listener returns false
            if (tree) {
                if (nextSibling) {
                    el = Ext.DomHelper.insertBefore(nextSibling, tree);
                }
                else {
                    el = Ext.DomHelper.append(container, tree);
                }
 
                me.wrapPrimaryEl(el);
 
                // Just rendered a bunch of stuff so fill up the cache with those els we will need.
                me.cacheRefEls(el);
            }
        }
        else {
            if (!me.hasListeners.beforerender || me.fireEvent('beforerender', me) !== false) {
                me.beforeRender();
 
                // We're simulating the above block here as much as possible, but we're already
                // given an el, so we don't need to create it. We still need to initialize
                // the renderTpl later.
                me.needsRenderTpl = me.rendering = true;
                me._renderState = 2;
 
                // Set configured styles on pre-rendered Component's element
                me.initStyles(el);
 
                if (me.allowDomMove !== false) {
                    if (nextSibling) {
                        container.dom.insertBefore(el.dom, nextSibling);
                    }
                    else {
                        container.dom.appendChild(el.dom);
                    }
                }
            }
            else {
                vetoed = true;
            }
        }
 
        if (el && !vetoed) {
            me.finishRender(position);
        }
 
        if (!me.skipLayout) {
            Ext.resumeLayouts(!me.hidden && !container.isDetachedBody);
        }
    },
 
    /**
     * Ensures that this component is attached to `document.body`. If the component was
     * rendered to {@link Ext#getDetachedBody}, then it will be appended to `document.body`.
     * Any configured position is also restored.
     * @param {Boolean} [runLayout=false] True to run the component's layout.
     */
    ensureAttachedToBody: function(runLayout) {
        var comp = this,
            body;
 
        while (comp.ownerCt) {
            comp = comp.ownerCt;
        }
 
        if (comp.container.isDetachedBody) {
            comp.container = body = Ext.getBody();
            body.appendChild(comp.el.dom);
 
            if (runLayout) {
                comp.updateLayout();
            }
 
            if (typeof comp.x === 'number' || typeof comp.y === 'number') {
                comp.setPosition(comp.x, comp.y);
            }
        }
    },
 
    //=========================================================================
 
    privates: {
        /**
         * Sets references to elements inside the component. This applies
         * {@link Ext.Component#cfg-renderSelectors renderSelectors} as well as
         * {@link Ext.Component#cfg-childEls childEls}.
         * @private
         */
        applyRenderSelectors: function() {
            var me = this,
                selectors = me.renderSelectors,
                el = me.el,
                query, selector;
 
            me.attachChildEls(el);
 
            // Cache focusEl as a property for speedier lookups
            if (typeof me.focusEl === 'string') {
                me.focusEl = me[me.focusEl];
            }
 
            // For the majority of Components, their ariaEl is going to be their main el.
            me.ariaEl = me[me.ariaEl] || me.el;
 
            // We still support renderSelectors. There are a few places in the framework that
            // need them and they are a documented part of the API. In fact, we support mixing
            // childEls and renderSelectors (no reason not to).
            if (selectors) {
                for (selector in selectors) {
                    query = selectors[selector];
 
                    if (query) {
                        me[selector] = el.selectNode(query, false);
                    }
                }
            }
        },
 
        /**
         * Ensures that all elements with "data-ref" attributes get loaded into the cache.
         * This really helps on IE8 where `getElementById` is a search not a lookup. By
         * populating our cache with one search of the DOM we then have random access to
         * the elements as we do our `childEls` wire up.
         * @private
         */
        cacheRefEls: function(el) {
            el = el || this.el;
 
            // eslint-disable-next-line vars-on-top
            var cache = Ext.cache,
                El = Ext.dom.Element,
                dom = el.isElement ? el.dom : el,
                refs = dom.querySelectorAll('[data-ref]'),
                len = refs.length,
                ref, i;
 
            for (= 0; i < len; i++) {
                ref = refs[i];
 
                if (!cache[ref.id]) {
                    new El(ref);
                }
            }
        },
 
        /**
         * Handles autoRender.
         * Floating Components may have an ownerCt. If they are asking to be constrained,
         * constrain them within that ownerCt, and have their z-index managed locally.
         * Floating Components are always rendered to document.body
         * @private
         */
        doAutoRender: function() {
            var me = this;
 
            if (!me.rendered) {
                if (me.floating) {
                    me.render(me.renderTo || document.body);
                }
                else {
                    me.render(Ext.isBoolean(me.autoRender) ? Ext.getBody() : me.autoRender);
                }
            }
        },
 
        doRenderContent: function(out, renderData) {
            // Careful! This method is bolted on to the renderTpl so all we get for context is
            // the renderData! The "this" pointer is the renderTpl instance!
            var me = renderData.$comp,
                data = me.data;
 
            if (me.html) {
                Ext.DomHelper.generateMarkup(me.html, out);
                delete me.html;
            }
 
            if (me.tpl) {
                // Make sure this.tpl is an instantiated XTemplate
                if (!me.tpl.isTemplate) {
                    me.tpl = new Ext.XTemplate(me.tpl);
                }
 
                if (data) {
                    me.data = data = data.isEntity ? data.getData(true) : data;
                    // me.tpl[me.tplWriteMode](target, me.data);
                    me.tpl.applyOut(data, out);
                }
            }
        },
 
        doRenderFramingTabGuard: function(out, renderData, position) {
            // Careful! This method is bolted on to the frameTpl so all we get for context is
            // the renderData! The "this" pointer is the frameTpl instance!
 
            // Container layout implements doRenderTabGuard(), *not* Component itself!
            var layout = renderData.$comp.layout;
 
            // The "renderData" property is placed in scope for the renderTpl, but we don't
            // want to render tab guards at that level in addition to the framing level:
            renderData.renderData.$skipTabGuards = true;
 
            if (layout && layout.doRenderTabGuard) {
                layout.doRenderTabGuard.call(this, out, renderData, position);
            }
        },
 
        flushRenderConfigs: function() {
            var me = this,
                configs = me.renderConfigs,
                state = me._renderState,
                bucket, i, name, newConfigs, value;
 
            if (configs) {
                for (= 0; i <= state; ++i) {
                    bucket = configs[i];
 
                    if (bucket) {
                        configs[i] = null;
 
                        for (name in bucket) {
                            value = bucket[name];
                            (newConfigs || (newConfigs = {}))[name] = me[name];
                            me[name] = value;
                        }
                    }
                }
 
                if (newConfigs) {
                    me.setConfig(newConfigs);
                }
            }
        },
 
        /**
         * This method visits the rendered component tree in a "top-down" order. That is, this
         * code runs on a parent component before running on a child. This method calls the
         * {@link #onRender} method of each component.
         * @param {Number} containerIdx The index into the Container items of this Component.
         *
         * @private
         */
        finishRender: function(containerIdx) {
            var me = this,
                cache = Ext.cache, // our element cache
                proxy, first, id, tpl, data, dom, el;
 
            // We are typically called w/me.el==null as a child of some ownerCt that is being
            // rendered. We are also called by render for a normal component (w/o a configured
            // me.el). In this case, render sets me.el and me.rendering (indirectly). Lastly
            // we are also called on a component (like a Viewport) that has a configured me.el
            // (body for a Viewport) when render is called. In this case, it is not flagged as
            // "me.rendering" yet because it does not produce a renderTree. We use this to know
            // not to regen the renderTpl.
 
            if (!me.el || me.$pid) {
                if (me.container) {
                    el = cache[me.id];
                    dom = el ? el.dom : me.container.getById(me.id, true);
                }
                else {
                    id = me.$pid || me.id;
                    el = cache[id];
                    dom = el ? el.dom : Ext.getDom(id);
                }
 
                if (!me.el) {
                    // Typical case: we produced the el during render
                    me.wrapPrimaryEl(dom);
                }
                else {
                    // We were configured with an el and created a proxy, so now we can swap
                    // the proxy for me.el:
                    delete me.$pid;
 
                    if (!me.el.dom) {
                        // make sure me.el is an Element
                        me.wrapPrimaryEl(me.el);
                    }
 
                    // Insert the configured el before the proxy el:
                    dom.parentNode.insertBefore(me.el.dom, dom);
 
                    // We need to transplant rendered content from the proxy to the
                    // configured el. This would included the renderTpl of the component
                    // and its layout (innerCt's and such) as well as all child items.
                    //
                    proxy = dom; // hold on to the rendered DOM
                    dom = me.el.dom; // we'll be using the configured el though
                    first = dom.firstChild; // rendered content in proxy goes first
 
                    while (proxy.firstChild) {
                        dom.insertBefore(proxy.firstChild, first);
                    }
 
                    // We need the classes rendered on to the proxy as well (things like
                    // "x-panel"):
                    me.el.addCls(proxy.className);
 
                    Ext.removeNode(proxy); // now proxy can go
                    // TODO - what about style?
                }
            }
            else if (me.needsRenderTpl) {
                // We were configured with an el and then told to render (e.g., Viewport). We
                // need to generate the proper DOM. Insert first because the layout system
                // insists that child Component elements indices match the Component indices.
                tpl = me.initRenderTpl();
 
                if (tpl) {
                    data = me.initRenderData();
                    tpl.insertFirst(me.getTargetEl(), data);
                }
 
                // Just rendered a bunch of stuff so fill up the cache with those els we
                // will need.
                me.cacheRefEls();
            }
            // else we are rendering
 
            me.el.component = me;
 
            if (!me.container) {
                // top-level rendered components will already have me.container set up
                me.container = Ext.get(me.el.dom.parentNode);
            }
 
            if (me.ctCls) {
                me.container.addCls(me.ctCls);
            }
 
            // Sets the rendered flag and clears the rendering flag
            me.onRender(me.container, containerIdx);
 
            // If we could not access a target protoEl in beforeRender,
            // we have to set the overflow styles here.
            if (!me.overflowInited) {
                me.initOverflow();
            }
 
            // Tell the encapsulating element to hide itself in the way the Component
            // is configured to hide. This means DISPLAY, VISIBILITY or OFFSETS.
            me.el.setVisibilityMode(Ext.Element[me.hideMode.toUpperCase()]);
 
            if (me.overCls) {
                me.el.hover(me.addOverCls, me.removeOverCls, me);
            }
 
            if (me.hasListeners.render) {
                me.fireEvent('render', me);
            }
 
            me.afterRender(); // this can cause a layout
 
            if (me.hasListeners.afterrender) {
                me.fireEvent('afterrender', me);
            }
 
            me.initEvents();
 
            if (me.hidden) {
                // Hiding during the render process should not perform any ancillary
                // actions that the full hide process does; It is not hiding,
                // it begins in a hidden state.
                // So just make the element hidden according to the configured hideMode
                me.el.hide();
            }
        },
 
        finishRenderChildren: function() {
            var layout = this.getComponentLayout();
 
            layout.finishRender();
        },
 
        getFrameRenderData: function() {
            var me = this,
                // we are only called if framing so this has already been determined:
                frameInfo = me.frameSize,
                mcStyle = '';
 
            //<feature legacyBrowser>
            if (me._syncFrameHeight && me.height) {
                // Buttons need their frame's MC element to have an explicit height in order
                // for percentage heights to work on elements inside the frame
                mcStyle = 'height:' + (me.height - frameInfo.height) + 'px';
            }
            //</feature>
 
            return {
                $comp: me,
                id: me.id,
                fgid: me.id + '-frame',
                ui: me.ui,
                uiCls: me.uiCls,
                frameCls: me.frameCls,
                frameBodyCls: me.layoutTargetCls || '',
                baseCls: me.baseCls,
                hasTabGuard: me.tabGuard,
                top: !!frameInfo.top,
                left: !!frameInfo.left,
                right: !!frameInfo.right,
                bottom: !!frameInfo.bottom,
                mcStyle: mcStyle,
                // can be optionally set by a subclass or override to be an extra class to
                // be applied to all framing elements (used by RTL)
                frameElCls: ''
            };
        },
 
        /**
         * @private
         * On render, reads an encoded style attribute, "filter" from the style of this Component's
         * element. This information is memoized based upon the CSS class name of this Component's
         * element. Because child Components are rendered as textual HTML as part of the topmost
         * Container, a dummy div is inserted into the document to receive the document element's
         * CSS class name, and therefore style attributes.
         */
        getFrameInfo: function() {
            // If native framing can be used, or this component is not going to be framed,
            // then do not attempt to read CSS framing info.
            if (Ext.supports.CSS3BorderRadius || !this.frame) {
                return false;
            }
 
            // eslint-disable-next-line vars-on-top
            var me = this,
                frameInfoCache = me.frameInfoCache,
                cls = me.getFramingInfoCls() + '-frameInfo',
                frameInfo = frameInfoCache[cls],
                styleEl, info, frameTop, frameRight, frameBottom, frameLeft,
                borderTopWidth, borderRightWidth, borderBottomWidth, borderLeftWidth,
                paddingTop, paddingRight, paddingBottom, paddingLeft;
 
            if (frameInfo == null) {
                // Get the singleton frame style proxy with our el class name stamped into it.
                styleEl = Ext.fly(me.getStyleProxy(cls), 'frame-style-el');
                info = styleEl.getStyle('font-family');
                info = info && info.split('-');
 
                if (info && info.length >= 5) {
                    // The framing data is encoded as
                    //
                    //         D=div|T=table
                    //         |   H=horz|V=vert
                    //         |   |
                    //         |   |
                    //        [DT][HV]-[T-R-B-L]-[T-R-B-L]-[T-R-B-L]
                    //                /       /  |       |  \      \
                    //              /        /   |       |   \      \
                    //            /         /   /         \   \      \
                    //          /          /    border-width   \      \
                    //          frame-size                      padding
                    //
                    // The first 2 chars hold the div/table and horizontal/vertical flags.
                    // The 3 sets of TRBL 4-tuples are the CSS3 values for border-radius,
                    // border-width and padding, respectively.
                    //
 
                    /* eslint-disable no-multi-spaces */
                    frameTop          = parseInt(info[1], 10);
                    frameRight        = parseInt(info[2], 10);
                    frameBottom       = parseInt(info[3], 10);
                    frameLeft         = parseInt(info[4], 10);
 
                    borderTopWidth    = parseInt(info[5], 10) || 0;
                    borderRightWidth  = parseInt(info[6], 10) || 0;
                    borderBottomWidth = parseInt(info[7], 10) || 0;
                    borderLeftWidth   = parseInt(info[8], 10) || 0;
                    paddingTop        = parseInt(info[9], 10) || 0;
                    paddingRight      = parseInt(info[10], 10) || 0;
                    paddingBottom     = parseInt(info[11], 10) || 0;
                    paddingLeft       = parseInt(info[12], 10) || 0;
                    /* eslint-enable no-multi-spaces */
 
                    frameInfo = {
                        table: info[0].charAt(0) === 't',
                        vertical: info[0].charAt(1) === 'v',
 
                        top: frameTop,
                        right: frameRight,
                        bottom: frameBottom,
                        left: frameLeft,
 
                        // Ext.layout.ContextItem needs width/height
                        width: frameLeft + frameRight,
                        height: frameTop + frameBottom,
 
                        border: {
                            top: borderTopWidth,
                            right: borderRightWidth,
                            bottom: borderBottomWidth,
                            left: borderLeftWidth,
                            width: borderLeftWidth + borderRightWidth,
                            height: borderTopWidth + borderBottomWidth
                        },
                        padding: {
                            top: paddingTop,
                            right: paddingRight,
                            bottom: paddingBottom,
                            left: paddingLeft,
                            width: paddingLeft + paddingRight,
                            height: paddingTop + paddingBottom
                        }
                    };
                }
                else {
                    frameInfo = false;
                }
 
                //<debug>
                // This happens when you set frame: true explicitly without using the x-frame mixin
                // in sass.
                // This way IE can't figure out what sizes to use and thus framing can't work.
                if (me.frame === true && !frameInfo) {
                    Ext.log.error(
                        'You have set frame: true explicity on this component (' + me.getXType() +
                        ') and it does not have any framing defined in the CSS template. ' +
                        'In this case IE cannot figure out what sizes to use and thus framing ' +
                        'on this component will be disabled.'
                    );
                }
                //</debug>
 
                frameInfoCache[cls] = frameInfo;
            }
 
            me.frame = !!frameInfo;
            me.frameSize = frameInfo;
 
            return frameInfo;
        },
 
        getFramingInfoCls: function() {
            return this.baseCls + '-' + this.ui;
        },
 
        /**
         * @private
         * Returns an offscreen div with the same class name as the element this is being rendered.
         * This is because child item rendering takes place in a detached div which, being not
         * part of the document, has no styling.
         */
        getStyleProxy: function(cls) {
            var result;
 
            result = this.styleProxyEl ||
                    (Ext.Component.prototype.styleProxyEl = Ext.getBody().createChild({
                        //<debug>
                        // tell the spec runner to ignore this element
                        // when checking if the dom is clean
                        'data-sticky': true,
                        //</debug>
                        role: 'presentation',
                        style: {
                            position: 'absolute',
                            top: '-10000px'
                        }
                    }, null, true));
 
            result.className = cls;
 
            return result;
        },
 
        /**
         * @private
         */
        getFrameTpl: function(table) {
            return this.lookupTpl(table ? 'frameTableTpl' : 'frameTpl');
        },
 
        initContainer: function(container) {
            var me = this;
 
            // If you render a component specifying the el, we get the container
            // of the el, and make sure we dont move the el around in the dom
            // during the render
            if (!container && me.el) {
                container = me.el.dom.parentNode;
                me.allowDomMove = false;
            }
 
            me.container = container.dom ? container : Ext.get(container);
 
            return me.container;
        },
 
        initOverflow: function() {
            var me = this,
                // Call the style calculation early which sets the scrollFlags property
                overflowStyle = me.getOverflowStyle(),
                scrollFlags = me.scrollFlags,
                overflowEl = me.getOverflowEl(),
                hasOverflow = (scrollFlags.y || scrollFlags.x);
 
            // Not rendered, or the targetEl has been configured as a string, 
            // wait until the call from finishRender
            if (!hasOverflow || !overflowEl || !overflowEl.isElement) {
                return;
            }
 
            me.overflowInited = true;
 
            overflowEl.setStyle(overflowStyle);
        },
 
        // Create the framingTpl from the string.
        // Poke in a reference to applyRenderTpl(frameInfo, out)
        initFramingTpl: function(table) {
            var tpl = this.getFrameTpl(table);
 
            if (tpl && !tpl.applyRenderTpl) {
                this.setupFramingTpl(tpl);
            }
 
            return tpl;
        },
 
        /**
         * Initializes the renderTpl.
         * @return {Ext.XTemplate} The renderTpl XTemplate instance.
         * @private
         */
        initRenderTpl: function() {
            var tpl = this.lookupTpl('renderTpl');
 
            if (tpl && !tpl.renderContent) {
                this.setupRenderTpl(tpl);
            }
 
            return tpl;
        },
 
        /**
         * @private
         * Inject a reference to the function which applies the render template
         * into the framing template. The framing template wraps the content.
         */
        setupFramingTpl: function(frameTpl) {
            frameTpl.applyRenderTpl = this.doApplyRenderTpl;
            frameTpl.renderTabGuard = this.doRenderFramingTabGuard;
        },
 
        setupRenderTpl: function(renderTpl) {
            renderTpl.renderBody = renderTpl.renderContent = this.doRenderContent;
        },
 
        /**
         * Updates the frame elements to match new framing. The current `frameBody` is
         * preserved by transplanting it into the new frame. All other frame `childEls`
         * are destroyed and recreated if needed by the new frame. This method cannot
         * transition from framed to non-framed or vise-versa or between table and div
         * based framing.
         * @private
         */
        updateFrame: function() {
            if (Ext.supports.CSS3BorderRadius || !this.frame) {
                return;
            }
 
            // eslint-disable-next-line vars-on-top
            var me = this,
                dom = me.el.dom,
                frameTable = me.frameTable,
                oldFrameBody = me.frameBody,
                oldFrameBodyDom = oldFrameBody.dom,
                frameInfo = me.getFrameInfo(),
                childEls, childElName, div, el, first, frameData, frameDom, frameTpl, i,
                newBody, newFrameEls;
 
            // This is a bit tricky because we will be generating elements with the same
            // id's (mostly) as our current frame. We have to do most of this work with
            // the raw DOM nodes due to the duplicate id's (which prevents us from using
            // an Element wrapper until we resolve the duplicates).
 
            // First off, render the new frameTpl to an off-document element.
            div = document.createElement('div');
            frameData = me.getFrameRenderData();
 
            // If the container was configured with tab guards, they were already rendered.
            frameData.hasTabGuard = false;
 
            frameTpl = me.getFrameTpl(frameInfo.table);
            frameTpl.insertFirst(div, frameData);
 
            // Capture the new frameEls (we'll need to update our childEls to these later
            // once we've destroyed the old ones).
            newFrameEls = div.querySelectorAll('[data-ref]');
            newBody = div.querySelector('[data-ref="frameBody"]');
 
            // Now we can insert the new frameEls before the current frameBody.
            for (first = oldFrameBodyDom; first.parentNode !== dom;) {
                first = first.parentNode;
            }
 
            while (div.firstChild) {
                dom.insertBefore(div.firstChild, first);
            }
 
            // And transplant the oldFrameBody into the new frame
            newBody.parentNode.replaceChild(oldFrameBodyDom, newBody);
            oldFrameBodyDom.className = newBody.className;
            oldFrameBody.setSize(); // clear any size set by layout
 
            // Remove the old frame elements, except for frameBody of course:
            childEls = me.getChildEls();
 
            if (frameTable) {
                frameTable.destroy();
                me.frameTable = null;
            }
 
            for (childElName in childEls) {
                if (childEls[childElName].frame) {
                    el = me[childElName];
 
                    if (el && el !== oldFrameBody) {
                        el.destroy();
                        me[childElName] = null;
                    }
                }
            }
 
            // Now we are free to acquire the childEls to the new elements:
            for (= newFrameEls.length; i--;) {
                childElName = (frameDom = newFrameEls[i]).getAttribute('data-ref');
 
                if (childElName !== 'frameBody') {
                    me[childElName] = new Ext.dom.Element(frameDom);
                }
            }
        },
 
        // Cache the frame information object so as not to cause style recalculations
        frameInfoCache: {}
    } // private
});