UNPKG

8.86 kBJavaScriptView Raw
1import { View, CSSType } from '../core/view';
2import { LayoutBase } from '../layouts/layout-base';
3import { Property } from '../core/properties';
4import { Trace } from '../../trace';
5/**
6 * Proxy view container that adds all its native children directly to the parent.
7 * To be used as a logical grouping container of views.
8 */
9// Cases to cover:
10// * Child is added to the attached proxy. Handled in _addViewToNativeVisualTree.
11// * Proxy (with children) is added to the DOM. In _addViewToNativeVisualTree _addViewToNativeVisualTree recursively when the proxy is added to the parent.
12// * Child is removed from attached proxy. Handled in _removeViewFromNativeVisualTree.
13// * Proxy (with children) is removed form the DOM. In _removeViewFromNativeVisualTree recursively when the proxy is removed from its parent.
14let ProxyViewContainer = class ProxyViewContainer extends LayoutBase {
15 constructor() {
16 super();
17 this.proxiedLayoutProperties = new Set();
18 this.nativeViewProtected = undefined;
19 }
20 // No native view for proxy container.
21 // @ts-ignore
22 get ios() {
23 return null;
24 }
25 // @ts-ignore
26 get android() {
27 return null;
28 }
29 // get nativeView(): any {
30 // return null;
31 // }
32 get isLayoutRequested() {
33 // Always return false so all layout requests from children bubble up.
34 return false;
35 }
36 createNativeView() {
37 return undefined;
38 }
39 _getNativeViewsCount() {
40 let result = 0;
41 this.eachChildView((cv) => {
42 result += cv._getNativeViewsCount();
43 return true;
44 });
45 return result;
46 }
47 _eachLayoutView(callback) {
48 this.eachChildView((cv) => {
49 if (!cv.isCollapsed) {
50 cv._eachLayoutView(callback);
51 }
52 return true;
53 });
54 }
55 _setupUI(context, atIndex, parentIsLoaded) {
56 let processChildren = false;
57 if (this.reusable && this._context === context) {
58 processChildren = true;
59 }
60 super._setupUI(context, atIndex, parentIsLoaded);
61 if (this.reusable && processChildren) {
62 this.eachChild((child) => {
63 const oldReusable = child.reusable;
64 child.reusable = true;
65 child._setupUI(context);
66 child.reusable = oldReusable;
67 return true;
68 });
69 }
70 }
71 _tearDownUI(force) {
72 super._tearDownUI(force);
73 if (this.reusable && !force) {
74 this.eachChild((child) => {
75 const oldReusable = child.reusable;
76 child.reusable = true;
77 child._tearDownUI();
78 child.reusable = oldReusable;
79 return true;
80 });
81 }
82 }
83 _addViewToNativeVisualTree(child, atIndex) {
84 if (Trace.isEnabled()) {
85 Trace.write('ProxyViewContainer._addViewToNativeVisualTree for a child ' + child + ' ViewContainer.parent: ' + this.parent, Trace.categories.ViewHierarchy);
86 }
87 super._addViewToNativeVisualTree(child);
88 layoutProperties.forEach((propName) => {
89 const proxyPropName = makeProxyPropName(propName);
90 child[proxyPropName] = child[propName];
91 if (this.proxiedLayoutProperties.has(propName)) {
92 this._applyLayoutPropertyToChild(child, propName, this[propName]);
93 }
94 });
95 const parent = this.parent;
96 if (parent instanceof View) {
97 let baseIndex = 0;
98 let insideIndex = 0;
99 if (parent instanceof LayoutBase) {
100 // Get my index in parent and convert it to native index.
101 baseIndex = parent._childIndexToNativeChildIndex(parent.getChildIndex(this));
102 }
103 if (atIndex !== undefined) {
104 insideIndex = this._childIndexToNativeChildIndex(atIndex);
105 }
106 else {
107 // Add last;
108 insideIndex = this._getNativeViewsCount();
109 }
110 if (Trace.isEnabled()) {
111 Trace.write('ProxyViewContainer._addViewToNativeVisualTree at: ' + atIndex + ' base: ' + baseIndex + ' additional: ' + insideIndex, Trace.categories.ViewHierarchy);
112 }
113 return parent._addViewToNativeVisualTree(child, baseIndex + insideIndex);
114 }
115 return false;
116 }
117 _removeViewFromNativeVisualTree(child) {
118 if (Trace.isEnabled()) {
119 Trace.write('ProxyViewContainer._removeViewFromNativeVisualTree for a child ' + child + ' ViewContainer.parent: ' + this.parent, Trace.categories.ViewHierarchy);
120 }
121 super._removeViewFromNativeVisualTree(child);
122 const parent = this.parent;
123 if (parent instanceof View) {
124 return parent._removeViewFromNativeVisualTree(child);
125 }
126 }
127 /*
128 * Some layouts (e.g. GridLayout) need to get notified when adding and
129 * removing children, so that they can update private measure data.
130 *
131 * We register our children with the parent to avoid breakage.
132 */
133 _registerLayoutChild(child) {
134 const parent = this.parent;
135 if (parent instanceof LayoutBase) {
136 parent._registerLayoutChild(child);
137 }
138 }
139 _unregisterLayoutChild(child) {
140 const parent = this.parent;
141 if (parent instanceof LayoutBase) {
142 parent._unregisterLayoutChild(child);
143 }
144 }
145 /*
146 * Register/unregister existing children with the parent layout.
147 */
148 _parentChanged(oldParent) {
149 // call super in order to execute base logic like clear inherited properties, etc.
150 super._parentChanged(oldParent);
151 const addingToParent = this.parent && !oldParent;
152 const newLayout = this.parent;
153 const oldLayout = oldParent;
154 if (addingToParent && newLayout instanceof LayoutBase) {
155 this.eachLayoutChild((child) => {
156 newLayout._registerLayoutChild(child);
157 return true;
158 });
159 }
160 else if (oldLayout instanceof LayoutBase) {
161 this.eachLayoutChild((child) => {
162 oldLayout._unregisterLayoutChild(child);
163 return true;
164 });
165 }
166 }
167 /**
168 * Layout property changed, proxy the new value to the child view(s)
169 */
170 _changedLayoutProperty(propName, value) {
171 const numChildren = this._getNativeViewsCount();
172 if (numChildren > 1) {
173 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);
174 }
175 this.eachLayoutChild((child) => {
176 this._applyLayoutPropertyToChild(child, propName, value);
177 return true;
178 });
179 this.proxiedLayoutProperties.add(propName);
180 }
181 /**
182 * Apply the layout property to the child view.
183 */
184 _applyLayoutPropertyToChild(child, propName, value) {
185 const proxyPropName = makeProxyPropName(propName);
186 if (proxyPropName in child) {
187 if (child[propName] !== child[proxyPropName]) {
188 // Value was set directly on the child view, don't override.
189 if (Trace.isEnabled()) {
190 Trace.write('ProxyViewContainer._applyLayoutPropertyToChild child ' + child + ' has its own value [' + child[propName] + '] for [' + propName + ']', Trace.categories.ViewHierarchy);
191 }
192 return;
193 }
194 }
195 child[propName] = value;
196 child[proxyPropName] = value;
197 }
198};
199ProxyViewContainer = __decorate([
200 CSSType('ProxyViewContainer'),
201 __metadata("design:paramtypes", [])
202], ProxyViewContainer);
203export { ProxyViewContainer };
204// Layout propeties to be proxyed to the child views
205const layoutProperties = [
206 // AbsoluteLayout
207 'left',
208 'top',
209 // DockLayout
210 'dock',
211 // FlexLayout
212 'flexDirection',
213 'flexWrap',
214 'justifyContent',
215 'alignItems',
216 'alignContent',
217 'order',
218 'flexGrow',
219 'flexShrink',
220 'flexWrapBefore',
221 'alignSelf',
222 'flexFlow',
223 'flex',
224 // GridLayout
225 'column',
226 'columnSpan',
227 'col',
228 'colSpan',
229 'row',
230 'rowSpan',
231];
232// Override the inherited layout properties
233for (const name of layoutProperties) {
234 const proxyProperty = new Property({
235 name,
236 valueChanged(target, oldValue, value) {
237 target._changedLayoutProperty(name, value);
238 },
239 });
240 proxyProperty.register(ProxyViewContainer);
241}
242function makeProxyPropName(propName) {
243 return `_proxy:${propName}`;
244}
245//# sourceMappingURL=index.js.map
\No newline at end of file