/** * A flyweight Ext.dom.Element that can be dynamically attached to a DOM node. * In general this class should not be instantiated directly. Use {@link Ext#fly} * to create and retrieve Fly instances. */Ext.define('Ext.dom.Fly', { extend: 'Ext.dom.Element', alternateClassName: 'Ext.dom.Element.Fly', // This adds the ability to wrap DOCUMENT_FRAGMENT_NODE // Document Fragments cannot have event listeners and therefore do not // need the caching mechanism provided by Ext.get. // However the many Element APIs are useful such as Traversal, child appending/removing. validNodeTypes: { 1: 1, // ELEMENT_NODE 9: 1, // DOCUMENT_NODE 11: 1 // DOCUMENT_FRAGMENT_NODE }, /** * @property {Boolean} isFly * This is `true` to identify Element flyweights */ isFly: true, constructor: function(dom) { this.dom = dom; // set an "el" property that references "this". This allows // Ext.util.Positionable methods to operate on this.el.dom since it // gets mixed into both Element and Component this.el = this; }, attach: function(dom) { var me = this, data; if (!dom) { return me.detach(); } // Sometimes we want to attach to the DOM of Ext.Element instance me.dom = Ext.getDom(dom); // If the element is not being managed by an Ext.Element instance, // we have to assume that the classList/classMap in the data object are out of sync // with reality. if (!Ext.cache[dom.id]) { data = me.peekData(); if (data) { data.isSynchronized = false; } } return me; }, detach: function() { return (this.dom = null); }, addListener: //<debug> function() { Ext.raise( "Cannot use addListener() on Ext.dom.Fly instances. " + "Please use Ext.get() to retrieve an Ext.dom.Element instance instead." ); } || //</debug> null, removeListener: //<debug> function() { Ext.raise( "Cannot use removeListener() on Ext.dom.Fly instances. " + "Please use Ext.get() to retrieve an Ext.dom.Element instance instead." ); } || //</debug> null}, function(Fly) { var flyweights = {}, detachedBodyEl; /** * @member Ext * @property {Object} cache * Stores `Fly` instances keyed by their assigned or generated name. * @readonly * @private * @since 5.0.0 */ Fly.cache = flyweights; /** * @member Ext * @method fly * Gets the globally shared flyweight Element, with the passed node as the active * element. Do not store a reference to this element - the dom node can be overwritten * by other code. {@link Ext#fly} is alias for {@link Ext.dom.Element#fly}. * * Use this to make one-time references to DOM elements which are not going to be * accessed again either by application code, or by Ext's classes. If accessing an * element which will be processed regularly, then {@link Ext#get Ext.get} will be * more appropriate to take advantage of the caching provided by the * {@link Ext.dom.Element} class. * * If this method is called with and id or element that has already been cached by * a previous call to Ext.get() it will return the cached Element instead of the * flyweight instance. * * @param {String/HTMLElement} dom The DOM node or `id`. * @param {String} [named] Allows for creation of named reusable flyweights to prevent * conflicts (e.g. internally Ext uses "_global"). * @return {Ext.dom.Element} The shared Element object (or `null` if no matching * element was found). */ Ext.fly = function(dom, named) { var fly = null, fn = Ext.fly, nodeType, data; // name the flyweight after the calling method name if possible. named = named || (fn.caller && (fn.caller.$name || fn.caller.name)) || '_global'; dom = Ext.getDom(dom); if (dom) { nodeType = dom.nodeType; // check if we have a valid node type or if the el is a window object before // proceeding. This allows elements, document fragments, and document/window // objects (even those inside iframes) to be wrapped. // Note: a window object can be detected by comparing it's window property to // itself, but we must use == for the comparison because === will return false // in IE8 even though the 2 window objects are the same /* eslint-disable-next-line eqeqeq */ if (Fly.prototype.validNodeTypes[nodeType] || (!nodeType && (dom.window == dom))) { fly = Ext.cache[dom.id]; // If there's no Element cached, or the element cached is for another DOM node, // return a Fly if (!fly || fly.dom !== dom) { // Since the `flyweights` map is simply an object, it has the `constructor` // property, just like any object, so to prevent the `Ext.fly` from failing // when it's called from the `constructor` method, we use the `$constructor` // as the key. if (named === 'constructor') { named = '$constructor'; } fly = flyweights[named] || (flyweights[named] = new Fly()); fly.dom = dom; data = fly.peekData(); if (data) { data.isSynchronized = false; } } } } return fly; }; /** * Returns an HTML div element into which {@link Ext.container.Container#method-remove removed} * components are placed so that their DOM elements are not garbage collected as detached * Dom trees. * @return {Ext.dom.Element} * @method getDetachedBody * @member Ext * @private */ Ext.getDetachedBody = function() { if (!detachedBodyEl) { Ext.detachedBodyEl = detachedBodyEl = new Fly(document.createElement('div')); detachedBodyEl.isDetachedBody = true; } return detachedBodyEl; };});