Implements: Proxy layout properties for the ProxyViewContainer (#8150)

* feat(ProxyViewContainer): proxy layout properties to children

* update import path

* fix(ProxyViewContainer): Layout properties not applied to new children

* test(ProxyViewContainer): Add test for layout properties

* chore: fix tslint errors
This commit is contained in:
Morten Sjøgren
2019-12-02 10:13:23 +01:00
committed by Alexander Vakrilov
parent 3199a392b4
commit 2bb7ad9d01
2 changed files with 129 additions and 1 deletions

View File

@ -1,5 +1,8 @@
import { ProxyViewContainer as ProxyViewContainerDefinition } from ".";
import { LayoutBase, View, traceEnabled, traceWrite, traceCategories, CSSType } from "../layouts/layout-base";
import { Property } from "../core/properties/properties";
import { messageType } from "../../trace/trace";
/**
* Proxy view container that adds all its native children directly to the parent.
* To be used as a logical grouping container of views.
@ -11,6 +14,7 @@ import { LayoutBase, View, traceEnabled, traceWrite, traceCategories, CSSType }
// * Proxy (with children) is removed form the DOM. In _removeViewFromNativeVisualTree recursively when the proxy is removed from its parent.
@CSSType("ProxyViewContainer")
export class ProxyViewContainer extends LayoutBase implements ProxyViewContainerDefinition {
private proxiedLayoutProperties = new Set<string>();
constructor() {
super();
@ -62,10 +66,19 @@ export class ProxyViewContainer extends LayoutBase implements ProxyViewContainer
public _addViewToNativeVisualTree(child: View, atIndex?: number): boolean {
if (traceEnabled()) {
traceWrite("ViewContainer._addViewToNativeVisualTree for a child " + child + " ViewContainer.parent: " + this.parent, traceCategories.ViewHierarchy);
traceWrite("ProxyViewContainer._addViewToNativeVisualTree for a child " + child + " ViewContainer.parent: " + this.parent, traceCategories.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;
@ -147,4 +160,90 @@ export class ProxyViewContainer extends LayoutBase implements ProxyViewContainer
});
}
}
/**
* Layout property changed, proxy the new value to the child view(s)
*/
public _changedLayoutProperty(propName: string, value: string) {
const numChildren = this._getNativeViewsCount();
if (numChildren > 1) {
traceWrite("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 ", traceCategories.ViewHierarchy, messageType.error);
}
this.eachLayoutChild((child) => {
this._applyLayoutPropertyToChild(child, propName, value);
return true;
});
this.proxiedLayoutProperties.add(propName);
}
/**
* Apply the layout property to the child view.
*/
private _applyLayoutPropertyToChild(child: View, propName: string, value: any) {
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 (traceEnabled()) {
traceWrite("ProxyViewContainer._applyLayoutPropertyToChild child " + child + " has its own value [" + child[propName] + "] for [" + propName + "]", traceCategories.ViewHierarchy);
}
return;
}
}
child[propName] = value;
child[proxyPropName] = value;
}
}
// 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<ProxyViewContainer, string>({
name,
valueChanged(target, oldValue, value) {
target._changedLayoutProperty(name, value);
}
});
proxyProperty.register(ProxyViewContainer);
}
function makeProxyPropName(propName) {
return `_proxy:${propName}`;
}

View File

@ -43,6 +43,35 @@ export function test_children_immediately_registered_in_parent_grid_layout() {
helper.buildUIAndRunTest(outer, testAction);
}
export function test_proxy_layout_properties() {
const outer = new GridLayout();
const proxy = new ProxyViewContainer();
function testAction(views: Array<View>) {
outer.addChild(proxy);
const btn = createBtn("1");
proxy.addChild(btn);
proxy.row = 1;
TKUnit.assertEqual(proxy.row, btn.row, "Proxy row value to existing child");
const btn2 = createBtn("2");
proxy.addChild(btn2);
TKUnit.assertEqual(proxy.row, btn2.row, "Proxy row value to new child");
proxy.removeChild(btn2);
btn.row = 0;
TKUnit.assertNotEqual(proxy.row, btn.row, "Child value changed");
proxy.row = 1;
TKUnit.assertNotEqual(proxy.row, btn.row, "Changed child value not overridden");
}
helper.buildUIAndRunTest(outer, testAction);
}
export function test_children_registered_in_parent_grid_layout_on_attach() {
const outer = new GridLayout();
const proxy = new ProxyViewContainer();