UNPKG

@nativescript/core

Version:

A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.

247 lines • 8.89 kB
import { View, CSSType } from '../core/view'; import { LayoutBase } from '../layouts/layout-base'; import { Property } from '../core/properties'; import { Trace } from '../../trace'; /** * Proxy view container that adds all its native children directly to the parent. * To be used as a logical grouping container of views. * * @nsView ProxyViewContainer */ // Cases to cover: // * Child is added to the attached proxy. Handled in _addViewToNativeVisualTree. // * Proxy (with children) is added to the DOM. In _addViewToNativeVisualTree _addViewToNativeVisualTree recursively when the proxy is added to the parent. // * Child is removed from attached proxy. Handled in _removeViewFromNativeVisualTree. // * Proxy (with children) is removed form the DOM. In _removeViewFromNativeVisualTree recursively when the proxy is removed from its parent. let ProxyViewContainer = class ProxyViewContainer extends LayoutBase { constructor() { super(); this.proxiedLayoutProperties = new Set(); this.nativeViewProtected = undefined; } // No native view for proxy container. // @ts-ignore get ios() { return null; } // @ts-ignore get android() { return null; } // get nativeView(): any { // return null; // } get isLayoutRequested() { // Always return false so all layout requests from children bubble up. return false; } createNativeView() { return undefined; } _getNativeViewsCount() { let result = 0; this.eachChildView((cv) => { result += cv._getNativeViewsCount(); return true; }); return result; } _eachLayoutView(callback) { this.eachChildView((cv) => { if (!cv.isCollapsed) { cv._eachLayoutView(callback); } return true; }); } _setupUI(context, atIndex, parentIsLoaded) { let processChildren = false; if (this.reusable && this._context === context) { processChildren = true; } super._setupUI(context, atIndex, parentIsLoaded); if (this.reusable && processChildren) { this.eachChild((child) => { const oldReusable = child.reusable; child.reusable = true; child._setupUI(context); child.reusable = oldReusable; return true; }); } } _tearDownUI(force) { super._tearDownUI(force); if (this.reusable && !force) { this.eachChild((child) => { const oldReusable = child.reusable; child.reusable = true; child._tearDownUI(); child.reusable = oldReusable; return true; }); } } _addViewToNativeVisualTree(child, atIndex) { if (Trace.isEnabled()) { Trace.write('ProxyViewContainer._addViewToNativeVisualTree for a child ' + child + ' ViewContainer.parent: ' + this.parent, Trace.categories.ViewHierarchy); } super._addViewToNativeVisualTree(child); layoutProperties.forEach((propName) => { const proxyPropName = makeProxyPropName(propName); child[proxyPropName] = child[propName]; if (this.proxiedLayoutProperties.has(propName)) { this._applyLayoutPropertyToChild(child, propName, this[propName]); } }); const parent = this.parent; if (parent instanceof View) { let baseIndex = 0; let insideIndex = 0; if (parent instanceof LayoutBase) { // Get my index in parent and convert it to native index. baseIndex = parent._childIndexToNativeChildIndex(parent.getChildIndex(this)); } if (atIndex !== undefined) { insideIndex = this._childIndexToNativeChildIndex(atIndex); } else { // Add last; insideIndex = this._getNativeViewsCount(); } if (Trace.isEnabled()) { Trace.write('ProxyViewContainer._addViewToNativeVisualTree at: ' + atIndex + ' base: ' + baseIndex + ' additional: ' + insideIndex, Trace.categories.ViewHierarchy); } return parent._addViewToNativeVisualTree(child, baseIndex + insideIndex); } return false; } _removeViewFromNativeVisualTree(child) { if (Trace.isEnabled()) { Trace.write('ProxyViewContainer._removeViewFromNativeVisualTree for a child ' + child + ' ViewContainer.parent: ' + this.parent, Trace.categories.ViewHierarchy); } super._removeViewFromNativeVisualTree(child); const parent = this.parent; if (parent instanceof View) { return parent._removeViewFromNativeVisualTree(child); } } /* * Some layouts (e.g. GridLayout) need to get notified when adding and * removing children, so that they can update private measure data. * * We register our children with the parent to avoid breakage. */ _registerLayoutChild(child) { const parent = this.parent; if (parent instanceof LayoutBase) { parent._registerLayoutChild(child); } } _unregisterLayoutChild(child) { const parent = this.parent; if (parent instanceof LayoutBase) { parent._unregisterLayoutChild(child); } } /* * Register/unregister existing children with the parent layout. */ _parentChanged(oldParent) { // call super in order to execute base logic like clear inherited properties, etc. super._parentChanged(oldParent); const addingToParent = this.parent && !oldParent; const newLayout = this.parent; const oldLayout = oldParent; if (addingToParent && newLayout instanceof LayoutBase) { this.eachLayoutChild((child) => { newLayout._registerLayoutChild(child); return true; }); } else if (oldLayout instanceof LayoutBase) { this.eachLayoutChild((child) => { oldLayout._unregisterLayoutChild(child); return true; }); } } /** * Layout property changed, proxy the new value to the child view(s) */ _changedLayoutProperty(propName, value) { const numChildren = this._getNativeViewsCount(); if (numChildren > 1) { Trace.write("ProxyViewContainer._changeLayoutProperty - you're setting '" + propName + "' for " + this + ' with more than one child. Probably this is not what you want, consider wrapping it in a StackLayout ', Trace.categories.ViewHierarchy, Trace.messageType.error); } this.eachLayoutChild((child) => { this._applyLayoutPropertyToChild(child, propName, value); return true; }); this.proxiedLayoutProperties.add(propName); } /** * Apply the layout property to the child view. */ _applyLayoutPropertyToChild(child, propName, value) { const proxyPropName = makeProxyPropName(propName); if (proxyPropName in child) { if (child[propName] !== child[proxyPropName]) { // Value was set directly on the child view, don't override. if (Trace.isEnabled()) { Trace.write('ProxyViewContainer._applyLayoutPropertyToChild child ' + child + ' has its own value [' + child[propName] + '] for [' + propName + ']', Trace.categories.ViewHierarchy); } return; } } child[propName] = value; child[proxyPropName] = value; } }; ProxyViewContainer = __decorate([ CSSType('ProxyViewContainer'), __metadata("design:paramtypes", []) ], ProxyViewContainer); export { ProxyViewContainer }; // Layout propeties to be proxyed to the child views const layoutProperties = [ // AbsoluteLayout 'left', 'top', // DockLayout 'dock', // FlexLayout 'flexDirection', 'flexWrap', 'justifyContent', 'alignItems', 'alignContent', 'order', 'flexGrow', 'flexShrink', 'flexWrapBefore', 'alignSelf', 'flexFlow', 'flex', // GridLayout 'column', 'columnSpan', 'col', 'colSpan', 'row', 'rowSpan', ]; // Override the inherited layout properties for (const name of layoutProperties) { const proxyProperty = new Property({ name, valueChanged(target, oldValue, value) { target._changedLayoutProperty(name, value); }, }); proxyProperty.register(ProxyViewContainer); } function makeProxyPropName(propName) { return `_proxy:${propName}`; } //# sourceMappingURL=index.js.map