/** * @private * Common methods for both classic & modern containers */Ext.define('Ext.mixin.Container', { extend: 'Ext.Mixin', mixinConfig: { id: 'container' }, /* * @property {Boolean} isContainer * `true` in this class to identify an object as an instantiated Container, or subclass thereof. */ isContainer: true, config: { /** * @cfg {Boolean} referenceHolder * If `true`, this container will be marked as being a point in the hierarchy where * references to items with a specified `reference` config will be held. The container * will automatically become a referenceHolder if a {@link #controller} is specified. * * See the introductory docs for {@link Ext.container.Container} for more information * about references & reference holders. */ referenceHolder: false }, /** * Returns an object holding the descendants of this view keyed by their * `{@link Ext.Component#cfg-reference reference}`. This object should not be held * past the scope of the function calling this method. It will not be valid if items * are added or removed from this or any sub-container. * * The intended usage is shown here (assume there are 3 components with reference * values of "foo", "bar" and "baz" at some level below this container): * * onClick: function () { * var refs = this.getReferences(); * * // using "refs" we can access any descendant by its "reference" * * refs.foo.getValue() + refs.bar.getValue() + refs.baz.getValue(); * } * * If `this` component has a `{@link Ext.Component#cfg-reference reference}` assigned * to it, that is **not** included in this object. That reference is understood to * belong to the ancestor container configured as the `referenceHolder`. * * @return {Object} An object with each child reference. This will be `null` if this * container has no descendants with a `{@link Ext.Component#cfg-reference reference}` * specified. * @since 5.0.0 */ getReferences: function () { Ext.ComponentManager.fixReferences(); return this.refs || null; }, /** * Gets a reference to a child specified using the {@link #reference} configuration. * * @param {String} key The name of the reference. * @return {Ext.Component} The referenced component or `null` if it is not found. */ lookupReference: function (key) { var refs = this.getReferences(); return (refs && refs[key]) || null; }, privates: { /** * Sets up a component reference. * @param {Ext.Component} component The component to reference. * @private */ attachReference: function (component) { var me = this, key, refs; // Cleaning all this up later anyway if (me.destroying || me.destroyed) { return; } refs = me.refs || (me.refs = {}); key = component.referenceKey; //<debug> if (refs[key] && refs[key] !== component) { Ext.log.warn('Duplicate reference: "' + key + '" on ' + me.id); } //</debug> refs[key] = component; }, /** * Clear a component reference. * @param {Ext.Component} component The component to remove. * @private */ clearReference: function (component) { var refs = this.refs, key = component.referenceKey; if (refs && key) { // viewModelKey would be better placed in app.Container however // it's not really worth introducing a second method call to clear // a single property. component.viewModelKey = component.referenceKey = refs[key] = null; } }, containerOnAdded: function(component, instanced) { // We have been added to a container, we may have child references // or be a reference ourself. At this point we have no way of knowing if // our references are correct, so trigger a fix. if (instanced) { Ext.ComponentManager.markReferencesDirty(); } }, containerOnRemoved: function(destroying) { var refHolder; // If we're destroying this will get cleaned up anyway if (!destroying) { refHolder = this.lookupReferenceHolder(); if (refHolder) { // Clear any references here, they will be reset after the // next call to lookupReference after being marked dirty. // It's easier to wipe & re-establish them than attempt to // track what changed and prune the collection Ext.ComponentManager.markReferencesDirty(); refHolder.clearReferences(); } } }, /** * Invalidates the references collection. Typically called when * removing a container from this container, since it's difficult * to know what references got removed. * * @private */ clearReferences: function () { this.refs = null; }, initContainerInheritedState: function(inheritedState, inheritedStateInner) { var me = this, controller = me.getController(), session = me.getSession(), // Don't instantiate it here, we just want to know whether we // were configured with a VM viewModel = me.getConfig('viewModel', true), reference = me.getReference(), referenceHolder = me.getReferenceHolder(); if (controller) { inheritedState.referenceHolder = controller; referenceHolder = true; } else if (referenceHolder) { inheritedState.referenceHolder = me; } if (referenceHolder) { inheritedState.referencePath = ''; } else if (reference && me.isParentReference) { inheritedState.referencePath = me.referenceKey + '.'; } if (session) { inheritedState.session = session; } if (viewModel) { inheritedState.viewModelPath = ''; } else if (reference && me.isParentReference) { inheritedState.viewModelPath = me.viewModelKey + '.'; } }, setupReference: function(reference) { var len; if (reference && reference.charAt(len = reference.length - 1) === '>') { this.isParentReference = true; reference = reference.substring(0, len); } //<debug> if (reference && !Ext.validIdRe.test(reference)) { Ext.Error.raise('Invalid reference "' + reference + '" for ' + this.getId() + ' - not a valid identifier'); } //</debug> return reference; } }});