Fix for Button padding in android.

Fix for types - isString and isNumber.
Modified several tests to pass on VS Emulator for Android.
Fix page background to be applied in onLoaded method.
Enhancements for dependency-observable - it is now possible to add defaultValueGetter function to extract default value for a property. It can also be cached or not.
Remove android_constants because they are per theme and we cannot use them safely.
Fix for SearchBar reseColorProperty method.
This commit is contained in:
hshristov
2015-08-28 16:57:00 +03:00
parent c05cd6acb8
commit 3a0cc32ff2
20 changed files with 398 additions and 275 deletions

View File

@@ -369,7 +369,9 @@
<TypeScriptCompile Include="apps\ui-tests-app\pages\text\text-field.ts" />
<TypeScriptCompile Include="apps\ui-tests-app\pages\text\text-view.ts" />
<TypeScriptCompile Include="apps\ui-tests-app\pages\text\label.ts" />
<TypeScriptCompile Include="apps\ui-tests-app\pages\text\button.ts" />
<TypeScriptCompile Include="apps\ui-tests-app\pages\text\button.ts">
<DependentUpon>button.xml</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="apps\ui-tests-app\web-view\webview.ts">
<DependentUpon>webview.xml</DependentUpon>
</TypeScriptCompile>
@@ -795,7 +797,6 @@
</TypeScriptCompile>
<TypeScriptCompile Include="ui\text-view\text-view.d.ts" />
<TypeScriptCompile Include="ui\ui.ts" />
<TypeScriptCompile Include="utils\android_constants.ts" />
<TypeScriptCompile Include="utils\module-merge.ts" />
<TypeScriptCompile Include="utils\utils.android.ts">
<DependentUpon>utils.d.ts</DependentUpon>
@@ -1379,7 +1380,9 @@
<DependentUpon>styling.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\styling\styling.d.ts" />
<TypeScriptCompile Include="ui\styling\style-property.ts" />
<TypeScriptCompile Include="ui\styling\style-property.ts">
<DependentUpon>style-property.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\styling\converters.ts" />
<TypeScriptCompile Include="apps\tests\ui\label\label-tests.ts" />
<TypeScriptCompile Include="ui\tab-view\tab-view-common.ts">
@@ -1947,7 +1950,7 @@
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
<UserProperties ui_2scroll-view_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2editable-text-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2absolute-layout-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2gallery-app_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2content-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2web-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2linear-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2absolute-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2dock-layout_2package_1json__JSONSchema="" ui_2layouts_2grid-layout_2package_1json__JSONSchema="" ui_2layouts_2wrap-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" />
<UserProperties ui_2layouts_2wrap-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2grid-layout_2package_1json__JSONSchema="" ui_2layouts_2dock-layout_2package_1json__JSONSchema="" ui_2layouts_2absolute-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2linear-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2web-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2content-view_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2gallery-app_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2absolute-layout-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2editable-text-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2scroll-view_2package_1json__JSONSchema="http://json.schemastore.org/package" />
</VisualStudio>
</ProjectExtensions>
</Project>

View File

@@ -10,7 +10,6 @@ export function buttonTap(args) {
v.style._resetValue(style.fontSizeProperty);
v.style._resetValue(style.fontStyleProperty);
v.style._resetValue(style.fontWeightProperty);
v.style._resetValue(style.fontProperty);
v.style._resetValue(style.colorProperty);
v.style._resetValue(style.textAlignmentProperty);

View File

@@ -124,7 +124,7 @@ export function test_scrollabeHeight_vertical_orientation_when_content_is_big()
scrollView.content = btn;
waitForLayout();
TKUnit.assertEqual(scrollView.scrollableHeight, 200, "scrollView.scrollableHeight");
TKUnit.assertAreClose(scrollView.scrollableHeight, 200, 0.4, "scrollView.scrollableHeight");
TKUnit.assertEqual(scrollView.scrollableWidth, 0, "scrollView.scrollableWidth");
}
@@ -157,7 +157,7 @@ export function test_scrollabeWidth_horizontal_orientation_when_content_is_big()
waitForLayout();
TKUnit.assertEqual(scrollView.scrollableHeight, 0, "scrollView.scrollableHeight");
TKUnit.assertEqual(scrollView.scrollableWidth, 300, "scrollView.scrollableWidth");
TKUnit.assertAreClose(scrollView.scrollableWidth, 300, 0.4, "scrollView.scrollableWidth");
}
export function test_scrollToVerticalOffset_no_animation() {
@@ -174,7 +174,7 @@ export function test_scrollToVerticalOffset_no_animation() {
TKUnit.assertEqual(scrollView.verticalOffset, 0, "scrollView.verticalOffset");
scrollView.scrollToVerticalOffset(100, false);
TKUnit.assertEqual(scrollView.verticalOffset, 100, "scrollView.verticalOffset");
TKUnit.assertAreClose(scrollView.verticalOffset, 100, 0.1, "scrollView.verticalOffset");
}
export function test_scrollToVerticalOffset_with_animation() {
@@ -198,7 +198,7 @@ export function test_scrollToVerticalOffset_with_animation() {
TKUnit.waitUntilReady(() => { return scrollView.verticalOffset === 100 }, ASYNC);
// The scrolling animation should be finished by now
TKUnit.assertEqual(scrollView.verticalOffset, 100, "scrollView.verticalOffset");
TKUnit.assertAreClose(scrollView.verticalOffset, 100, 0.1, "scrollView.verticalOffset");
}
export function test_scrollToHorizontalOffset_no_animation() {
@@ -215,7 +215,7 @@ export function test_scrollToHorizontalOffset_no_animation() {
TKUnit.assertEqual(scrollView.horizontalOffset, 0, "scrollView.horizontalOffset");
scrollView.scrollToHorizontalOffset(100, false);
TKUnit.assertEqual(scrollView.horizontalOffset, 100, "scrollView.horizontalOffset");
TKUnit.assertAreClose(scrollView.horizontalOffset, 100, 0.1, "scrollView.horizontalOffset");
}
export function test_scrollToHorizontalOffset_with_animation() {
@@ -239,7 +239,7 @@ export function test_scrollToHorizontalOffset_with_animation() {
TKUnit.waitUntilReady(() => { return scrollView.horizontalOffset === 100 }, ASYNC);
// The scrolling animation should be finished by now
TKUnit.assertEqual(scrollView.horizontalOffset, 100, "scrollView.horizontalOffset");
TKUnit.assertAreClose(scrollView.horizontalOffset, 100, 0.1, "scrollView.horizontalOffset");
}
export function test_scrollView_persistsState_vertical() {
@@ -256,7 +256,7 @@ export function test_scrollView_persistsState_vertical() {
scrollView.scrollToVerticalOffset(100, false);
TKUnit.assertEqual(scrollView.verticalOffset, 100, "scrollView.verticalOffset before navigation");
TKUnit.assertAreClose(scrollView.verticalOffset, 100, 0.1, "scrollView.verticalOffset before navigation");
helper.do_PageTest_WithButton((t) => {
// Just navigate forward and back.
@@ -264,11 +264,11 @@ export function test_scrollView_persistsState_vertical() {
// Wait for the page to reload.
TKUnit.waitUntilReady(function () {
return scrollView.verticalOffset === 100;
return Math.abs(scrollView.verticalOffset - 100) < 0.1;
}, ASYNC);
// Check verticalOffset after navigation
TKUnit.assertEqual(scrollView.verticalOffset, 100, "scrollView.verticalOffset after navigation");
TKUnit.assertAreClose(scrollView.verticalOffset, 100, 0.1, "scrollView.verticalOffset after navigation");
}
export function test_scrollView_persistsState_horizontal() {
@@ -285,7 +285,7 @@ export function test_scrollView_persistsState_horizontal() {
scrollView.scrollToHorizontalOffset(100, false);
TKUnit.assertEqual(scrollView.horizontalOffset, 100, "scrollView.horizontalOffset before navigation");
TKUnit.assertAreClose(scrollView.horizontalOffset, 100, 0.1, "scrollView.horizontalOffset before navigation");
helper.do_PageTest_WithButton((t) => {
// Just navigate forward and back.
@@ -293,9 +293,9 @@ export function test_scrollView_persistsState_horizontal() {
// Wait for the page to reload.
TKUnit.waitUntilReady(function () {
return scrollView.horizontalOffset === 100;
return Math.abs(scrollView.horizontalOffset - 100) < 0.1;
}, ASYNC);
// Check verticalOffset after navigation
TKUnit.assertEqual(scrollView.horizontalOffset, 100, "scrollView.horizontalOffset after navigation");
TKUnit.assertAreClose(scrollView.horizontalOffset, 100, 0.1, "scrollView.horizontalOffset after navigation");
}

View File

@@ -70,7 +70,7 @@ export var testSearchBarFontSize = function () {
searchBar.style.fontSize = expectedValue;
actualValue = searchBarTestsNative.getNativeFontSize(searchBar);
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
TKUnit.assertAreClose(actualValue, expectedValue, 0.2);
});
};

View File

@@ -407,11 +407,11 @@ function property_binding_test(propName: string, firstValue: any, secondValue: a
view.bind(options, model);
actualResult = view.get(propName);
TKUnit.assert(actualResult === firstValue, "Actual result: " + actualResult + "; Expected result: " + firstValue);
TKUnit.assertEqual(actualResult, firstValue);
model.set(propName, secondValue);
actualResult = view.get(propName);
TKUnit.assert(actualResult === secondValue, "Actual result: " + actualResult + "; Expected result: " + secondValue);
TKUnit.assertEqual(actualResult, secondValue);
}
function property_binding_style_test(propName: string, firstValue: any, secondValue: any, view?: viewModule.View) {
@@ -431,11 +431,11 @@ function property_binding_style_test(propName: string, firstValue: any, secondVa
view.bind(options, model);
actualResult = view.style.get(propName);
TKUnit.assert(actualResult === firstValue, "Actual result: " + actualResult + "; Expected result: " + firstValue);
TKUnit.assertEqual(actualResult, firstValue);
model.set(propName, secondValue);
actualResult = view.style.get(propName);
TKUnit.assert(actualResult === secondValue, "Actual result: " + actualResult + "; Expected result: " + secondValue);
TKUnit.assertEqual(actualResult, secondValue);
}
export var test_binding_width = function () {
@@ -531,7 +531,7 @@ export var test_binding_style_minHeight = function () {
}
export var test_binding_style_margin = function () {
property_binding_style_test("margin", "1,1,1,1", "2,2,2,2");
property_binding_style_test("margin", "1 1 1 1", "2 2 2 2");
}
export var test_binding_style_marginLeft = function () {
@@ -551,7 +551,7 @@ export var test_binding_style_marginBottom = function () {
}
export var test_binding_style_padding = function () {
property_binding_style_test("padding", "1,1,1,1", "2,2,2,2");
property_binding_style_test("padding", "1 1 1 1", "2 2 2 2");
}
export var test_binding_style_paddingLeft = function () {
@@ -600,16 +600,16 @@ export var testIsVisible = function () {
var lbl = new label.Label();
helper.buildUIAndRunTest(lbl, function (views: Array<viewModule.View>) {
TKUnit.assert(lbl.visibility === enums.Visibility.visible, "Actual: " + lbl.visibility + "; Expected: " + enums.Visibility.visible);
TKUnit.assert(lbl._isVisible, "Actual: " + lbl._isVisible + "; Expected: true;");
TKUnit.assertEqual(lbl.visibility, enums.Visibility.visible);
TKUnit.assertEqual(lbl._isVisible, true);
lbl.visibility = enums.Visibility.collapse;
TKUnit.assert(lbl.visibility === enums.Visibility.collapse, "Actual: " + lbl.visibility + "; Expected: " + enums.Visibility.collapse);
TKUnit.assert(!lbl._isVisible, "Actual: " + lbl._isVisible + "; Expected: false;");
TKUnit.assertEqual(lbl.visibility, enums.Visibility.collapse);
TKUnit.assertEqual(lbl._isVisible, false);
lbl.visibility = enums.Visibility.collapsed;
TKUnit.assert(lbl.visibility === enums.Visibility.collapsed, "Actual: " + lbl.visibility + "; Expected: " + enums.Visibility.collapsed);
TKUnit.assert(!lbl._isVisible, "Actual: " + lbl._isVisible + "; Expected: false;");
TKUnit.assertEqual(lbl.visibility, enums.Visibility.collapsed);
TKUnit.assertEqual(lbl._isVisible, false);
});
}
@@ -632,7 +632,7 @@ export var testBorderWidth = function () {
var lbl = <label.Label>views[0];
var expectedValue = lbl.borderWidth;
var actualValue = definition.getNativeBorderWidth(lbl);
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
TKUnit.assertEqual(actualValue, expectedValue);
});
}
@@ -641,21 +641,21 @@ export var testCornerRadius = function () {
var lbl = <label.Label>views[0];
var expectedValue = lbl.borderRadius;
var actualValue = definition.getNativeCornerRadius(lbl);
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
TKUnit.assertEqual(actualValue, expectedValue);
});
}
export var testBorderColor = function () {
helper.buildUIAndRunTest(_createLabelWithBorder(), function (views: Array<viewModule.View>) {
var lbl = <label.Label>views[0];
TKUnit.assert(definition.checkNativeBorderColor(lbl), "BorderColor not applied correctly!");
TKUnit.assertEqual(definition.checkNativeBorderColor(lbl), true, "BorderColor not applied correctly!");
});
}
export var testBackgroundColor = function () {
helper.buildUIAndRunTest(_createLabelWithBorder(), function (views: Array<viewModule.View>) {
var lbl = <label.Label>views[0];
TKUnit.assert(definition.checkNativeBackgroundColor(lbl), "BackgroundColor not applied correctly!");
TKUnit.assertEqual(definition.checkNativeBackgroundColor(lbl), true, "BackgroundColor not applied correctly!");
});
}
@@ -665,7 +665,6 @@ export var testBackgroundImage = function () {
helper.buildUIAndRunTest(lbl, function (views: Array<viewModule.View>) {
var page = <page.Page>views[1];
page.css = ".myClass { background-image: url('~/logo.png') }";
TKUnit.assert(definition.checkNativeBackgroundImage(lbl), "Style background-image not loaded correctly.");
TKUnit.assertEqual(definition.checkNativeBackgroundImage(lbl), true, "Style background-image not loaded correctly.");
});
}

View File

@@ -8,9 +8,15 @@ export function resetStyles(args) {
v.style._resetValue(style.fontSizeProperty);
v.style._resetValue(style.fontStyleProperty);
v.style._resetValue(style.fontWeightProperty);
v.style._resetValue(style.fontProperty);
v.style._resetValue(style.colorProperty);
v.style._resetValue(style.textAlignmentProperty);
v.style._resetValue(style.paddingLeftProperty);
v.style._resetValue(style.paddingRightProperty);
v.style._resetValue(style.paddingTopProperty);
v.style._resetValue(style.paddingBottomProperty);
v.style._resetValue(style.borderColorProperty);
v.style._resetValue(style.borderWidthProperty);
v.style._resetValue(style.borderRadiusProperty);
return true;
});
}

View File

@@ -8,17 +8,19 @@
<WrapLayout>
<Button text="RESET" tap="resetStyles"/>
<Button text="normal" />
<Button text="color" style="color: green"/>
<Button text="size" style="font-size: 32" />
<Button text="italic" style="font-style: italic" />
<Button text="bold" style="font-weight: bold"/>
<Button text="bold-italic" style="font-weight: bold; font-style: italic"/>
<Button text="serif" style="font-family: serif"/>
<Button text="sans-serif" style="font-family: sans-serif"/>
<Button text="monospace" style="font-family: monospace"/>
<Button text="color" style="color: green"/>
<Button text="size" style="font-size: 32" />
<Button text="italic" style="font-style: italic" />
<Button text="bold" style="font-weight: bold"/>
<Button text="bold-italic" style="font-weight: bold; font-style: italic"/>
<Button text="serif" style="font-family: serif"/>
<Button text="sans-serif" style="font-family: sans-serif"/>
<Button text="monospace" style="font-family: monospace"/>
<Button text="Times New Roman" style="font-family: Times New Roman"/>
<Button text="invalid" style="font-family: InvalidFont"/>
<Button text="all in one" style="font-family: serif; font-weight: bold; font-style: italic; font-size: 32; color: green" />
<Button text="invalid" style="font-family: InvalidFont"/>
<Button text="all in one" style="font-family: serif; font-weight: bold; font-style: italic; font-size: 32; color: green" />
<Button text="padding on next" style="padding: 0"/>
<Button text="padding and borderWidth" style="padding: 0; border-width: 5; border-color: red; border-radius: 8"/>
</WrapLayout>
</StackLayout>
</Page>

View File

@@ -8,7 +8,6 @@ export function resetStyles(args) {
v.style._resetValue(style.fontSizeProperty);
v.style._resetValue(style.fontStyleProperty);
v.style._resetValue(style.fontWeightProperty);
v.style._resetValue(style.fontProperty);
v.style._resetValue(style.colorProperty);
v.style._resetValue(style.textAlignmentProperty);
return true;

View File

@@ -8,7 +8,6 @@ export function resetStyles(args) {
v.style._resetValue(style.fontSizeProperty);
v.style._resetValue(style.fontStyleProperty);
v.style._resetValue(style.fontWeightProperty);
v.style._resetValue(style.fontProperty);
v.style._resetValue(style.colorProperty);
v.style._resetValue(style.textAlignmentProperty);
return true;

View File

@@ -8,7 +8,6 @@ export function resetStyles(args) {
v.style._resetValue(style.fontSizeProperty);
v.style._resetValue(style.fontStyleProperty);
v.style._resetValue(style.fontWeightProperty);
v.style._resetValue(style.fontProperty);
v.style._resetValue(style.colorProperty);
v.style._resetValue(style.textAlignmentProperty);
return true;

View File

@@ -4,6 +4,15 @@
declare module "ui/core/dependency-observable" {
import observable = require("data/observable");
/**
* Interface used by Propery 'defaultValueGetter' function to specify if the default value returned by the native instance can be cached or not.
* One example is - android.widget.Button background. It is state drawable so it cannot be reused/cached.
*/
export interface NativeValueResult {
result: any;
cacheable: boolean;
}
/**
* Represents a special Property which supports changed callback, metadata and value validation.
*/
@@ -36,6 +45,12 @@ declare module "ui/core/dependency-observable" {
* Gets the valueConverter function associated with the property. This is a read-only property.
*/
valueConverter: (value: string) => any
/**
* Gets or sets the defaultValueGetter function used to get the default value for this property.
* If default value is 'undefined' and this property is set this function will be used to extract the default value from the native instance.
*/
defaultValueGetter: (instance: DependencyObservable) => NativeValueResult;
}
/**

View File

@@ -147,6 +147,8 @@ export class Property implements definition.Property {
this._valueConverter = valueConverter;
}
public defaultValueGetter: (instance: definition.DependencyObservable) => definition.NativeValueResult;
public get name(): string {
return this._name;
}
@@ -263,6 +265,8 @@ export class PropertyEntry implements definition.PropertyEntry {
}
}
var defaultValueForPropertyPerType: Map<string, any> = new Map<string, any>();
export class DependencyObservable extends observable.Observable {
private _propertyEntries = {};
@@ -310,6 +314,21 @@ export class DependencyObservable extends observable.Observable {
if (entry) {
return entry.effectiveValue;
}
else if (property.defaultValueGetter) { // we check for cached properties only for these which have 'defaultValueGetter' defined;
// When DependencyProperties are removed from Style - fix this check.
var view = (<any>this)._view || this;
let key = types.getClass(view) + "." + property.id;
let defaultValue = defaultValueForPropertyPerType.get(key);
if (types.isUndefined(defaultValue) && view._nativeView) {
let defaultValueResult = property.defaultValueGetter(this);
defaultValue = defaultValueResult.result;
if (defaultValueResult.cacheable) {
defaultValueForPropertyPerType.set(key, defaultValue);
}
}
return defaultValue;
}
return property.metadata.defaultValue;
}

View File

@@ -42,12 +42,12 @@ export class Page extends contentView.ContentView implements dts.Page {
constructor(options?: dts.Options) {
super(options);
this.actionBar = new actionBar.ActionBar();
// The default style of the page should be white background
this.style._setValue(styleModule.backgroundColorProperty, "white", dependencyObservable.ValueSource.Inherited);
}
public onLoaded() {
// The default style of the page should be white background
this.style._setValue(styleModule.backgroundColorProperty, "white", dependencyObservable.ValueSource.Inherited);
this._applyCss();
if (this.actionBarHidden !== undefined) {

View File

@@ -45,17 +45,25 @@ export class CssSelector {
}
public eachSetter(callback: (property: styleProperty.Property, resolvedValue: any) => void) {
var i,
property: styleProperty.Property,
resolvedValue;
for (let i = 0; i < this._declarations.length; i++) {
let declaration = this._declarations[i];
let name = declaration.property;
let resolvedValue = declaration.value;
let property = styleProperty.getPropertyByCssName(name);
for (i = 0; i < this._declarations.length; i++) {
property = styleProperty.getPropertyByCssName(this._declarations[i].property);
if (property) {
resolvedValue = this._declarations[i].value;
// The property.valueConverter is now used to convert the value later on in DependencyObservable._setValueInternal.
callback(property, resolvedValue);
}
else {
var pairs = styleProperty.getShorthandPairs(name, resolvedValue);
if (pairs) {
for (let j = 0; j < pairs.length; j++) {
let pair = pairs[j];
callback(pair.property, pair.value);
}
}
}
}
}
}

View File

@@ -2,6 +2,10 @@
import definition = require("ui/styling");
import observable = require("ui/core/dependency-observable");
export function getShorthandPairs(name: string, value: any): Array<KeyValuePair<Property, any>>;
export function registerShorthandCallback(name: string, callback: (value: any) => Array<KeyValuePair<Property, any>>): void;
export function getPropertyByName(name: string): Property;
export function getPropertyByCssName(name: string): Property;
@@ -16,4 +20,9 @@
cssName: string;
}
export interface KeyValuePair<K, V> {
property: K;
value: V;
}
}

View File

@@ -1,9 +1,10 @@
import definition = require("ui/styling");
import definition = require("ui/styling/style-property");
import types = require("utils/types");
import observable = require("ui/core/dependency-observable");
var propertiesByName = {};
var propertiesByCssName = {};
var callbackByShorthandName = new Map<string, (value: any) => Array<definition.KeyValuePair<definition.Property, any>>>();
var inheritableProperties: Array<Property> = [];
function registerProperty(property: Property) {
@@ -19,6 +20,23 @@ function registerProperty(property: Property) {
}
}
export function getShorthandPairs(name: string, value: any): Array<definition.KeyValuePair<definition.Property, any>> {
var callback = callbackByShorthandName.get(name);
if (callback) {
return callback(value)
}
return undefined;
}
export function registerShorthandCallback(name: string, callback: (value: any) => Array<definition.KeyValuePair<definition.Property, any>>): void {
if (callbackByShorthandName.has(name)) {
throw new Error("Shorthand callback already registered for property: " + name);
}
callbackByShorthandName.set(name, callback);
}
export function getPropertyByName(name: string): Property {
return propertiesByName[name];
}

View File

@@ -1,10 +1,9 @@
import styling = require("ui/styling");
import observable = require("ui/core/dependency-observable");
import color = require("color");
import types = require("utils/types");
import trace = require("trace");
import dependencyObservable = require("ui/core/dependency-observable");
import view = require("ui/core/view");
import {DependencyObservable, PropertyMetadata, PropertyMetadataSettings, PropertyChangeData, Property, ValueSource, NativeValueResult} from "ui/core/dependency-observable";
import {View} from "ui/core/view";
import {Color} from "color";
import stylers = require("ui/styling/stylers");
import styleProperty = require("ui/styling/style-property");
import converters = require("ui/styling/converters");
@@ -24,7 +23,7 @@ var _handlersCache = {};
var noStylingClasses = {};
// on Android we explicitly set propertySettings to None because android will invalidate its layout (skip unnecessary native call).
var AffectsLayout = global.android ? dependencyObservable.PropertyMetadataSettings.None : dependencyObservable.PropertyMetadataSettings.AffectsLayout;
var AffectsLayout = global.android ? PropertyMetadataSettings.None : PropertyMetadataSettings.AffectsLayout;
export interface Thickness {
left: number;
@@ -70,6 +69,9 @@ function parseThickness(value: any): Thickness {
} else if (types.isNumber(value)) {
result.top = result.right = result.bottom = result.left = value;
}
else {
result = value;
}
return result;
}
@@ -85,7 +87,7 @@ function layoutParamsComparer(x: CommonLayoutParams, y: CommonLayoutParams): boo
&& x.verticalAlignment === y.verticalAlignment
}
function onLayoutParamsChanged(data: observable.PropertyChangeData) {
function onLayoutParamsChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var layoutParams: CommonLayoutParams = {
width: isNaN(style.width) ? -1 : style.width,
@@ -101,7 +103,7 @@ function onLayoutParamsChanged(data: observable.PropertyChangeData) {
style._setValue(nativeLayoutParamsProperty, layoutParams);
}
function onPaddingValueChanged(data: observable.PropertyChangeData) {
function onPaddingValueChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var thickness: Thickness = {
top: style.paddingTop,
@@ -113,42 +115,11 @@ function onPaddingValueChanged(data: observable.PropertyChangeData) {
style._setValue(nativePaddingsProperty, thickness);
}
function onPaddingChanged(data: observable.PropertyChangeData) {
var thickness = parseThickness(data.newValue);
var style = <Style>data.object;
var valueSource = style._getValueSource(paddingProperty);
try {
style._beginUpdate();
style._setValue(paddingTopProperty, thickness.top, valueSource);
style._setValue(paddingRightProperty, thickness.right, valueSource);
style._setValue(paddingBottomProperty, thickness.bottom, valueSource);
style._setValue(paddingLeftProperty, thickness.left, valueSource);
}
finally {
style._endUpdate();
}
}
function onMarginChanged(data: observable.PropertyChangeData) {
var thickness = parseThickness(data.newValue);
var style = <Style>data.object;
var valueSource = style._getValueSource(marginProperty);
try {
style._beginUpdate();
style._setValue(marginTopProperty, thickness.top, valueSource);
style._setValue(marginRightProperty, thickness.right, valueSource);
style._setValue(marginBottomProperty, thickness.bottom, valueSource);
style._setValue(marginLeftProperty, thickness.left, valueSource);
}
finally {
style._endUpdate();
}
}
function thicknessComparer(x: Thickness, y: Thickness): boolean {
return x.left === y.left && x.top === y.top && x.right === y.right && x.bottom === y.bottom;
if (x && y) {
return x.left === y.left && x.top === y.top && x.right === y.right && x.bottom === y.bottom;
}
return !x === !y;
}
function isWidthHeightValid(value: number): boolean {
@@ -159,7 +130,7 @@ function isMinWidthHeightValid(value: number): boolean {
return !isNaN(value) && value >= 0.0 && isFinite(value);
}
function onBackgroundImagePropertyChanged(data: observable.PropertyChangeData) {
function onBackgroundImagePropertyChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var url: string = data.newValue;
var currentBackground = <background.Background>style._getValue(backgroundInternalProperty);
@@ -200,15 +171,15 @@ function onBackgroundImagePropertyChanged(data: observable.PropertyChangeData) {
}
}
function onBackgroundColorPropertyChanged(data: observable.PropertyChangeData) {
function onBackgroundColorPropertyChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var currentBackground = <background.Background>style._getValue(backgroundInternalProperty);
if (!color.Color.equals(currentBackground.color, data.newValue)) {
if (!Color.equals(currentBackground.color, data.newValue)) {
style._setValue(backgroundInternalProperty, currentBackground.withColor(data.newValue));
}
}
function onBackgroundSizePropertyChanged(data: observable.PropertyChangeData) {
function onBackgroundSizePropertyChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var currentBackground = <background.Background>style._getValue(backgroundInternalProperty);
if (data.newValue !== currentBackground.size) {
@@ -216,7 +187,7 @@ function onBackgroundSizePropertyChanged(data: observable.PropertyChangeData) {
}
}
function onBackgroundRepeatPropertyChanged(data: observable.PropertyChangeData) {
function onBackgroundRepeatPropertyChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var currentBackground = <background.Background>style._getValue(backgroundInternalProperty);
if (data.newValue !== currentBackground.repeat) {
@@ -224,7 +195,7 @@ function onBackgroundRepeatPropertyChanged(data: observable.PropertyChangeData)
}
}
function onBackgroundPositionPropertyChanged(data: observable.PropertyChangeData) {
function onBackgroundPositionPropertyChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var currentBackground = <background.Background>style._getValue(backgroundInternalProperty);
if (data.newValue !== currentBackground.position) {
@@ -244,7 +215,7 @@ function getHandlerInternal(propertyId: number, classInfo: types.ClassInfo): sty
var propertyHandlers = _registeredHandlers[propertyId];
if (noStylingClasses.hasOwnProperty(className) || !propertyHandlers) {
// Reached 'no-styling' class or no property handlers are registered for this proeprtyID
// Reached 'no-styling' class or no property handlers are registered for this propertyID
result = null;
}
else if (propertyHandlers.hasOwnProperty(className)) {
@@ -267,7 +238,7 @@ function isVisibilityValid(value: string): boolean {
return value === enums.Visibility.visible || value === enums.Visibility.collapse || value === enums.Visibility.collapsed;
}
function onVisibilityChanged(data: observable.PropertyChangeData) {
function onVisibilityChanged(data: PropertyChangeData) {
(<any>data.object)._view._isVisibleCache = data.newValue === enums.Visibility.visible;
}
@@ -292,7 +263,7 @@ function isFontStyleValid(value: string): boolean {
return value === enums.FontStyle.normal || value === enums.FontStyle.italic;
}
function onFontFamilyChanged(data: observable.PropertyChangeData) {
function onFontFamilyChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var currentFont = <font.Font>style._getValue(fontInternalProperty);
@@ -301,7 +272,7 @@ function onFontFamilyChanged(data: observable.PropertyChangeData) {
}
}
function onFontStyleChanged(data: observable.PropertyChangeData) {
function onFontStyleChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var currentFont = <font.Font>style._getValue(fontInternalProperty);
@@ -310,7 +281,7 @@ function onFontStyleChanged(data: observable.PropertyChangeData) {
}
}
function onFontWeightChanged(data: observable.PropertyChangeData) {
function onFontWeightChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var currentFont = <font.Font>style._getValue(fontInternalProperty);
@@ -319,7 +290,7 @@ function onFontWeightChanged(data: observable.PropertyChangeData) {
}
}
function onFontSizeChanged(data: observable.PropertyChangeData) {
function onFontSizeChanged(data: PropertyChangeData) {
var style = <Style>data.object;
var currentFont = <font.Font>style._getValue(fontInternalProperty);
@@ -328,260 +299,243 @@ function onFontSizeChanged(data: observable.PropertyChangeData) {
}
}
function onFontChanged(data: observable.PropertyChangeData) {
var style = <Style>data.object;
var newFont = font.Font.parse(data.newValue);
var valueSource = style._getValueSource(fontProperty);
try {
style._beginUpdate();
style._setValue(fontFamilyProperty, newFont.fontFamily, valueSource);
style._setValue(fontStyleProperty, newFont.fontStyle, valueSource);
style._setValue(fontWeightProperty, newFont.fontWeight, valueSource);
style._setValue(fontSizeProperty, newFont.fontSize, valueSource);
}
finally {
style._endUpdate();
}
}
export class Style extends observable.DependencyObservable implements styling.Style {
private _view: view.View;
export class Style extends DependencyObservable implements styling.Style {
private _view: View;
private _updateCounter = 0;
private _nativeSetters = new Map<dependencyObservable.Property, any>();
private _nativeSetters = new Map<Property, any>();
get color(): color.Color {
get color(): Color {
return this._getValue(colorProperty);
}
set color(value: color.Color) {
this._setValue(colorProperty, value, observable.ValueSource.Local);
set color(value: Color) {
this._setValue(colorProperty, value);
}
get backgroundColor(): color.Color {
get backgroundColor(): Color {
return this._getValue(backgroundColorProperty);
}
set backgroundColor(value: color.Color) {
this._setValue(backgroundColorProperty, value, observable.ValueSource.Local);
set backgroundColor(value: Color) {
this._setValue(backgroundColorProperty, value);
}
get backgroundImage(): string {
return this._getValue(backgroundImageProperty);
}
set backgroundImage(value: string) {
this._setValue(backgroundImageProperty, value, observable.ValueSource.Local);
this._setValue(backgroundImageProperty, value);
}
get backgroundRepeat(): string {
return this._getValue(backgroundRepeatProperty);
}
set backgroundRepeat(value: string) {
this._setValue(backgroundRepeatProperty, value, observable.ValueSource.Local);
this._setValue(backgroundRepeatProperty, value);
}
get backgroundSize(): string {
return this._getValue(backgroundSizeProperty);
}
set backgroundSize(value: string) {
this._setValue(backgroundSizeProperty, value, observable.ValueSource.Local);
this._setValue(backgroundSizeProperty, value);
}
get backgroundPosition(): string {
return this._getValue(backgroundPositionProperty);
}
set backgroundPosition(value: string) {
this._setValue(backgroundPositionProperty, value, observable.ValueSource.Local);
this._setValue(backgroundPositionProperty, value);
}
get borderColor(): color.Color {
get borderColor(): Color {
return this._getValue(borderColorProperty);
}
set borderColor(value: color.Color) {
this._setValue(borderColorProperty, value, observable.ValueSource.Local);
set borderColor(value: Color) {
this._setValue(borderColorProperty, value);
}
get borderWidth(): number {
return this._getValue(borderWidthProperty);
}
set borderWidth(value: number) {
this._setValue(borderWidthProperty, value, observable.ValueSource.Local);
this._setValue(borderWidthProperty, value);
}
get borderRadius(): number {
return this._getValue(borderRadiusProperty);
}
set borderRadius(value: number) {
this._setValue(borderRadiusProperty, value, observable.ValueSource.Local);
this._setValue(borderRadiusProperty, value);
}
get fontSize(): number {
return this._getValue(fontSizeProperty);
}
set fontSize(value: number) {
this._setValue(fontSizeProperty, value, observable.ValueSource.Local);
this._setValue(fontSizeProperty, value);
}
get fontFamily(): string {
return this._getValue(fontFamilyProperty);
}
set fontFamily(value: string) {
this._setValue(fontFamilyProperty, value, observable.ValueSource.Local);
this._setValue(fontFamilyProperty, value);
}
get fontStyle(): string {
return this._getValue(fontStyleProperty);
}
set fontStyle(value: string) {
this._setValue(fontStyleProperty, value, observable.ValueSource.Local);
this._setValue(fontStyleProperty, value);
}
get fontWeight(): string {
return this._getValue(fontWeightProperty);
}
set fontWeight(value: string) {
this._setValue(fontWeightProperty, value, observable.ValueSource.Local);
this._setValue(fontWeightProperty, value);
}
get font(): string {
return this._getValue(fontProperty);
return this.fontStyle + " " + this.fontWeight + " " + this.fontSize + " " + this.fontFamily;
}
set font(value: string) {
this._setValue(fontProperty, value, observable.ValueSource.Local);
this._setShorthandProperty("font", value);
}
get textAlignment(): string {
return this._getValue(textAlignmentProperty);
}
set textAlignment(value: string) {
this._setValue(textAlignmentProperty, value, observable.ValueSource.Local);
this._setValue(textAlignmentProperty, value);
}
get minWidth(): number {
return this._getValue(minWidthProperty);
}
set minWidth(value: number) {
this._setValue(minWidthProperty, value, observable.ValueSource.Local);
this._setValue(minWidthProperty, value);
}
get minHeight(): number {
return this._getValue(minHeightProperty);
}
set minHeight(value: number) {
this._setValue(minHeightProperty, value, observable.ValueSource.Local);
this._setValue(minHeightProperty, value);
}
get width(): number {
return this._getValue(widthProperty);
}
set width(value: number) {
this._setValue(widthProperty, value, observable.ValueSource.Local);
this._setValue(widthProperty, value);
}
get height(): number {
return this._getValue(heightProperty);
}
set height(value: number) {
this._setValue(heightProperty, value, observable.ValueSource.Local);
this._setValue(heightProperty, value);
}
get margin(): string {
return this._getValue(marginProperty);
return this.marginTop + " " + this.marginRight + " " + this.marginBottom + " " + this.marginLeft;
}
set margin(value: string) {
this._setValue(marginProperty, value, observable.ValueSource.Local);
this._setShorthandProperty("margin", value);
}
get marginLeft(): number {
return this._getValue(marginLeftProperty);
}
set marginLeft(value: number) {
this._setValue(marginLeftProperty, value, observable.ValueSource.Local);
this._setValue(marginLeftProperty, value);
}
get marginTop(): number {
return this._getValue(marginTopProperty);
}
set marginTop(value: number) {
this._setValue(marginTopProperty, value, observable.ValueSource.Local);
this._setValue(marginTopProperty, value);
}
get marginRight(): number {
return this._getValue(marginRightProperty);
}
set marginRight(value: number) {
this._setValue(marginRightProperty, value, observable.ValueSource.Local);
this._setValue(marginRightProperty, value);
}
get marginBottom(): number {
return this._getValue(marginBottomProperty);
}
set marginBottom(value: number) {
this._setValue(marginBottomProperty, value, observable.ValueSource.Local);
this._setValue(marginBottomProperty, value);
}
get padding(): string {
return this._getValue(paddingProperty);
return this.paddingTop + " " + this.paddingRight + " " + this.paddingBottom + " " + this.paddingLeft;
}
set padding(value: string) {
this._setValue(paddingProperty, value, observable.ValueSource.Local);
this._setShorthandProperty("padding", value);
}
get paddingLeft(): number {
return this._getValue(paddingLeftProperty);
}
set paddingLeft(value: number) {
this._setValue(paddingLeftProperty, value, observable.ValueSource.Local);
this._setValue(paddingLeftProperty, value);
}
get paddingTop(): number {
return this._getValue(paddingTopProperty);
}
set paddingTop(value: number) {
this._setValue(paddingTopProperty, value, observable.ValueSource.Local);
this._setValue(paddingTopProperty, value);
}
get paddingRight(): number {
return this._getValue(paddingRightProperty);
}
set paddingRight(value: number) {
this._setValue(paddingRightProperty, value, observable.ValueSource.Local);
this._setValue(paddingRightProperty, value);
}
get paddingBottom(): number {
return this._getValue(paddingBottomProperty);
}
set paddingBottom(value: number) {
this._setValue(paddingBottomProperty, value, observable.ValueSource.Local);
this._setValue(paddingBottomProperty, value);
}
get horizontalAlignment(): string {
return this._getValue(horizontalAlignmentProperty);
}
set horizontalAlignment(value: string) {
this._setValue(horizontalAlignmentProperty, value, observable.ValueSource.Local);
this._setValue(horizontalAlignmentProperty, value);
}
get verticalAlignment(): string {
return this._getValue(verticalAlignmentProperty);
}
set verticalAlignment(value: string) {
this._setValue(verticalAlignmentProperty, value, observable.ValueSource.Local);
this._setValue(verticalAlignmentProperty, value);
}
get visibility(): string {
return this._getValue(visibilityProperty);
}
set visibility(value: string) {
this._setValue(visibilityProperty, value, observable.ValueSource.Local);
this._setValue(visibilityProperty, value);
}
get opacity(): number {
return this._getValue(opacityProperty);
}
set opacity(value: number) {
this._setValue(opacityProperty, value, observable.ValueSource.Local);
this._setValue(opacityProperty, value);
}
constructor(parentView: view.View) {
constructor(parentView: View) {
super();
this._view = parentView;
}
@@ -595,6 +549,7 @@ export class Style extends observable.DependencyObservable implements styling.St
if (this._updateCounter < 0) {
throw new Error("style._endUpdate() called, but no update is in progress.");
}
if (this._updateCounter === 0) {
this._nativeSetters.forEach((newValue, property, map) => { this._applyStyleProperty(property, newValue); });
this._nativeSetters.clear();
@@ -603,21 +558,21 @@ export class Style extends observable.DependencyObservable implements styling.St
public _resetCssValues() {
var that = this;
this._eachSetProperty(function (property: observable.Property) {
that._resetValue(property, observable.ValueSource.Css);
this._eachSetProperty(function (property: Property) {
that._resetValue(property, ValueSource.Css);
return true;
});
}
public _resetLocalValues() {
var that = this;
this._eachSetProperty(function (property: observable.Property) {
that._resetValue(property, observable.ValueSource.Local);
this._eachSetProperty(function (property: Property) {
that._resetValue(property);
return true;
});
}
public _onPropertyChanged(property: dependencyObservable.Property, oldValue: any, newValue: any) {
public _onPropertyChanged(property: Property, oldValue: any, newValue: any) {
trace.write(
"Style._onPropertyChanged view:" + this._view +
", property: " + property.name +
@@ -643,7 +598,7 @@ export class Style extends observable.DependencyObservable implements styling.St
});
}
private _applyProperty(property: dependencyObservable.Property, newValue: any) {
private _applyProperty(property: Property, newValue: any) {
this._applyStyleProperty(property, newValue);
// The effective value of an inheritable property has changed
@@ -652,7 +607,7 @@ export class Style extends observable.DependencyObservable implements styling.St
return;
}
var eachChild = function (child: view.View): boolean {
var eachChild = function (child: View): boolean {
child.style._inheritStyleProperty(property);
return true;
}
@@ -660,7 +615,12 @@ export class Style extends observable.DependencyObservable implements styling.St
this._view._eachChildView(eachChild);
}
private _applyStyleProperty(property: dependencyObservable.Property, newValue: any) {
private _applyStyleProperty(property: Property, newValue: any) {
if (!this._view._nativeView) {
return;
}
if (this._updateCounter > 0) {
this._nativeSetters.set(property, newValue);
return;
@@ -695,7 +655,7 @@ export class Style extends observable.DependencyObservable implements styling.St
}
}
public _inheritStyleProperty(property: dependencyObservable.Property) {
public _inheritStyleProperty(property: Property) {
if (!property.metadata.inheritable) {
throw new Error("An attempt was made to inherit a style property which is not marked as 'inheritable'.");
}
@@ -705,8 +665,8 @@ export class Style extends observable.DependencyObservable implements styling.St
while (currentParent) {
valueSource = currentParent.style._getValueSource(property);
if (valueSource > dependencyObservable.ValueSource.Default) {
this._setValue(property, currentParent.style._getValue(property), dependencyObservable.ValueSource.Inherited);
if (valueSource > ValueSource.Default) {
this._setValue(property, currentParent.style._getValue(property), ValueSource.Inherited);
break;
}
@@ -720,9 +680,25 @@ export class Style extends observable.DependencyObservable implements styling.St
that._inheritStyleProperty(p);
});
}
get _nativeView(): any {
return this._view._nativeView;
}
private _setShorthandProperty(name: string, value: any): void {
var pairs = styleProperty.getShorthandPairs(name, value);
if (pairs) {
this._beginUpdate();
for (let j = 0; j < pairs.length; j++) {
let pair = pairs[j];
this._setValue(pair.property, pair.value, ValueSource.Local);
}
this._endUpdate();
}
}
}
export function registerHandler(property: dependencyObservable.Property, handler: styling.stylers.StylePropertyChangedHandler, className?: string) {
export function registerHandler(property: Property, handler: styling.stylers.StylePropertyChangedHandler, className?: string) {
var realClassName = className ? className : "default";
var handlerRecord = _registeredHandlers[property.id];
@@ -738,75 +714,76 @@ export function registerNoStylingClass(className) {
noStylingClasses[className] = 1;
}
export function getHandler(property: dependencyObservable.Property, view: view.View): styling.stylers.StylePropertyChangedHandler {
export function getHandler(property: Property, view: View): styling.stylers.StylePropertyChangedHandler {
return getHandlerInternal(property.id, types.getClassInfo(view));
}
// Property registration
export var colorProperty = new styleProperty.Property("color", "color",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.Inheritable, undefined, color.Color.isValid, color.Color.equals),
new PropertyMetadata(undefined, PropertyMetadataSettings.Inheritable, undefined, Color.isValid, Color.equals),
converters.colorConverter);
export var backgroundImageProperty = new styleProperty.Property("backgroundImage", "background-image",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.None, onBackgroundImagePropertyChanged));
new PropertyMetadata(undefined, PropertyMetadataSettings.None, onBackgroundImagePropertyChanged));
export var backgroundColorProperty = new styleProperty.Property("backgroundColor", "background-color",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.None, onBackgroundColorPropertyChanged, color.Color.isValid, color.Color.equals),
converters.colorConverter);
new PropertyMetadata(undefined, PropertyMetadataSettings.None, onBackgroundColorPropertyChanged, Color.isValid, Color.equals), converters.colorConverter);
export var backgroundRepeatProperty = new styleProperty.Property("backgroundRepeat", "background-repeat",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.None, onBackgroundRepeatPropertyChanged));
new PropertyMetadata(undefined, PropertyMetadataSettings.None, onBackgroundRepeatPropertyChanged));
export var backgroundSizeProperty = new styleProperty.Property("backgroundSize", "background-size",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.None, onBackgroundSizePropertyChanged));
new PropertyMetadata(undefined, PropertyMetadataSettings.None, onBackgroundSizePropertyChanged));
export var backgroundPositionProperty = new styleProperty.Property("backgroundPosition", "background-position",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.None, onBackgroundPositionPropertyChanged));
new PropertyMetadata(undefined, PropertyMetadataSettings.None, onBackgroundPositionPropertyChanged));
export var borderColorProperty = new styleProperty.Property("borderColor", "border-color",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.None, undefined, color.Color.isValid, color.Color.equals),
converters.colorConverter);
new PropertyMetadata(undefined, PropertyMetadataSettings.None, undefined, Color.isValid, Color.equals), converters.colorConverter);
export var borderWidthProperty = new styleProperty.Property("borderWidth", "border-width",
new observable.PropertyMetadata(0, AffectsLayout, null, isPaddingValid), converters.numberConverter);
new PropertyMetadata(0, AffectsLayout, null, isPaddingValid), converters.numberConverter);
export var borderRadiusProperty = new styleProperty.Property("borderRadius", "border-radius",
new observable.PropertyMetadata(0, AffectsLayout, null, isPaddingValid), converters.numberConverter);
new PropertyMetadata(0, AffectsLayout, null, isPaddingValid), converters.numberConverter);
export var backgroundInternalProperty = new styleProperty.Property("_backgroundInternal", "_backgroundInternal",
new observable.PropertyMetadata(background.Background.default, observable.PropertyMetadataSettings.None, undefined, undefined, background.Background.equals));
export var fontProperty = new styleProperty.Property("font", "font",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.None, onFontChanged));
new PropertyMetadata(background.Background.default, PropertyMetadataSettings.None, undefined, undefined, background.Background.equals));
export var fontSizeProperty = new styleProperty.Property("fontSize", "font-size",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.Inheritable, onFontSizeChanged), converters.fontSizeConverter);
new PropertyMetadata(undefined, PropertyMetadataSettings.Inheritable, onFontSizeChanged), converters.fontSizeConverter);
export var fontFamilyProperty = new styleProperty.Property("fontFamily", "font-family",
new observable.PropertyMetadata(undefined, observable.PropertyMetadataSettings.Inheritable, onFontFamilyChanged));
new PropertyMetadata(undefined, PropertyMetadataSettings.Inheritable, onFontFamilyChanged));
export var fontStyleProperty = new styleProperty.Property("fontStyle", "font-style",
new observable.PropertyMetadata(enums.FontStyle.normal, observable.PropertyMetadataSettings.Inheritable, onFontStyleChanged, isFontStyleValid));
new PropertyMetadata(enums.FontStyle.normal, PropertyMetadataSettings.Inheritable, onFontStyleChanged, isFontStyleValid));
export var fontWeightProperty = new styleProperty.Property("fontWeight", "font-weight",
new observable.PropertyMetadata(enums.FontWeight.normal, observable.PropertyMetadataSettings.Inheritable, onFontWeightChanged, isFontWeightValid));
new PropertyMetadata(enums.FontWeight.normal, PropertyMetadataSettings.Inheritable, onFontWeightChanged, isFontWeightValid));
export var fontInternalProperty = new styleProperty.Property("_fontInternal", "_fontInternal",
new observable.PropertyMetadata(font.Font.default, AffectsLayout, null, null, font.Font.equals), font.Font.parse);
new PropertyMetadata(font.Font.default, AffectsLayout, null, null, font.Font.equals), font.Font.parse);
export var textAlignmentProperty = new styleProperty.Property("textAlignment", "text-align",
new observable.PropertyMetadata(undefined, AffectsLayout | observable.PropertyMetadataSettings.Inheritable), converters.textAlignConverter);
new PropertyMetadata(undefined, AffectsLayout | PropertyMetadataSettings.Inheritable), converters.textAlignConverter);
export var minWidthProperty = new styleProperty.Property("minWidth", "min-width",
new observable.PropertyMetadata(0, AffectsLayout, null, isMinWidthHeightValid), converters.numberConverter);
new PropertyMetadata(0, AffectsLayout, null, isMinWidthHeightValid), converters.numberConverter);
export var minHeightProperty = new styleProperty.Property("minHeight", "min-height",
new observable.PropertyMetadata(0, AffectsLayout, null, isMinWidthHeightValid), converters.numberConverter);
new PropertyMetadata(0, AffectsLayout, null, isMinWidthHeightValid), converters.numberConverter);
export var visibilityProperty = new styleProperty.Property("visibility", "visibility",
new PropertyMetadata(enums.Visibility.visible, AffectsLayout, onVisibilityChanged, isVisibilityValid), converters.visibilityConverter);
export var opacityProperty = new styleProperty.Property("opacity", "opacity",
new PropertyMetadata(1.0, PropertyMetadataSettings.None, undefined, isOpacityValid), converters.opacityConverter);
// Helper property holding most layout related properties available in CSS.
// When layout related properties are set in CSS we chache them and send them to the native view in a single call.
export var nativeLayoutParamsProperty = new styleProperty.Property("nativeLayoutParams", "nativeLayoutParams",
new observable.PropertyMetadata({
new PropertyMetadata({
width: -1,
height: -1,
leftMargin: 0,
@@ -817,55 +794,118 @@ export var nativeLayoutParamsProperty = new styleProperty.Property("nativeLayout
verticalAlignment: enums.VerticalAlignment.stretch
}, null, null, null, layoutParamsComparer));
// Helper property holding all paddings. When paddings are set through CSS we cache them and send them to the native view in a single call.
export var nativePaddingsProperty = new styleProperty.Property("paddingNative", "paddingNative",
new observable.PropertyMetadata({ top: 0, right: 0, bottom: 0, left: 0 }, null, null, null, thicknessComparer));
export var widthProperty = new styleProperty.Property("width", "width",
new observable.PropertyMetadata(Number.NaN, AffectsLayout, onLayoutParamsChanged, isWidthHeightValid), converters.numberConverter);
new PropertyMetadata(Number.NaN, AffectsLayout, onLayoutParamsChanged, isWidthHeightValid), converters.numberConverter);
export var heightProperty = new styleProperty.Property("height", "height",
new observable.PropertyMetadata(Number.NaN, AffectsLayout, onLayoutParamsChanged, isWidthHeightValid), converters.numberConverter);
new PropertyMetadata(Number.NaN, AffectsLayout, onLayoutParamsChanged, isWidthHeightValid), converters.numberConverter);
export var verticalAlignmentProperty = new styleProperty.Property("verticalAlignment", "vertical-align",
new observable.PropertyMetadata(enums.VerticalAlignment.stretch, AffectsLayout, onLayoutParamsChanged));
new PropertyMetadata(enums.VerticalAlignment.stretch, AffectsLayout, onLayoutParamsChanged));
export var horizontalAlignmentProperty = new styleProperty.Property("horizontalAlignment", "horizontal-align",
new observable.PropertyMetadata(enums.HorizontalAlignment.stretch, AffectsLayout, onLayoutParamsChanged));
export var marginProperty = new styleProperty.Property("margin", "margin", new observable.PropertyMetadata(null, null, onMarginChanged));
new PropertyMetadata(enums.HorizontalAlignment.stretch, AffectsLayout, onLayoutParamsChanged));
export var marginLeftProperty = new styleProperty.Property("marginLeft", "margin-left",
new observable.PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
new PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
export var marginRightProperty = new styleProperty.Property("marginRight", "margin-right",
new observable.PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
new PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
export var marginTopProperty = new styleProperty.Property("marginTop", "margin-top",
new observable.PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
new PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
export var marginBottomProperty = new styleProperty.Property("marginBottom", "margin-bottom",
new observable.PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
new PropertyMetadata(0, AffectsLayout, onLayoutParamsChanged, isMarginValid), converters.numberConverter);
export var paddingProperty = new styleProperty.Property("padding", "padding", new observable.PropertyMetadata(null, null, onPaddingChanged));
function getNativePadding(nativeView: android.view.View, callback: (view: android.view.View) => number): NativeValueResult {
return {
result: nativeView ? callback(nativeView) / utils.layout.getDisplayDensity() : 0,
cacheable: !!nativeView
};
}
function getNativePaddingLeft(instance: DependencyObservable): NativeValueResult {
var nativeView: android.view.View = (<any>instance)._nativeView;
return getNativePadding(nativeView, (view) => { return view.getPaddingLeft(); });
}
function getNativePaddingTop(instance: DependencyObservable): NativeValueResult {
var nativeView: android.view.View = (<any>instance)._nativeView;
return getNativePadding(nativeView, (view) => { return view.getPaddingTop(); });
}
function getNativePaddingRight(instance: DependencyObservable): NativeValueResult {
var nativeView: android.view.View = (<any>instance)._nativeView;
return getNativePadding(nativeView, (view) => { return view.getPaddingRight(); });
}
function getNativePaddingBottom(instance: DependencyObservable): NativeValueResult {
var nativeView: android.view.View = (<any>instance)._nativeView;
return getNativePadding(nativeView, (view) => { return view.getPaddingBottom(); });
}
// Helper property holding all paddings. When paddings are set through CSS we cache them and send them to the native view in a single call.
export var nativePaddingsProperty = new styleProperty.Property("paddingNative", "paddingNative",
new PropertyMetadata(undefined, null, null, null, thicknessComparer));
// TODO: separate into .android/.ios files so that there is no need for such checks
var defaultPadding = global.android ? undefined : 0;
export var paddingLeftProperty = new styleProperty.Property("paddingLeft", "padding-left",
new observable.PropertyMetadata(0, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
new PropertyMetadata(defaultPadding, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
export var paddingRightProperty = new styleProperty.Property("paddingRight", "padding-right",
new observable.PropertyMetadata(0, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
new PropertyMetadata(defaultPadding, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
export var paddingTopProperty = new styleProperty.Property("paddingTop", "padding-top",
new observable.PropertyMetadata(0, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
new PropertyMetadata(defaultPadding, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
export var paddingBottomProperty = new styleProperty.Property("paddingBottom", "padding-bottom",
new observable.PropertyMetadata(0, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
new PropertyMetadata(defaultPadding, AffectsLayout, onPaddingValueChanged, isPaddingValid), converters.numberConverter);
export var visibilityProperty = new styleProperty.Property("visibility", "visibility",
new observable.PropertyMetadata(enums.Visibility.visible, AffectsLayout, onVisibilityChanged, isVisibilityValid), converters.visibilityConverter);
// TODO: separate into .android/.ios files so that there is no need for such checks
if (global.android) {
paddingTopProperty.defaultValueGetter = getNativePaddingTop;
paddingLeftProperty.defaultValueGetter = getNativePaddingLeft;
paddingRightProperty.defaultValueGetter = getNativePaddingRight;
paddingBottomProperty.defaultValueGetter = getNativePaddingBottom;
}
export var opacityProperty = new styleProperty.Property("opacity", "opacity",
new observable.PropertyMetadata(1.0, observable.PropertyMetadataSettings.None, undefined, isOpacityValid), converters.opacityConverter);
function onPaddingChanged(value: any): Array<styleProperty.KeyValuePair<styleProperty.Property, any>> {
var thickness = parseThickness(value);
var array = new Array<styleProperty.KeyValuePair<styleProperty.Property, any>>();
array.push({ property: paddingTopProperty, value: thickness.top });
array.push({ property: paddingRightProperty, value: thickness.right });
array.push({ property: paddingBottomProperty, value: thickness.bottom });
array.push({ property: paddingLeftProperty, value: thickness.left });
return array;
}
function onMarginChanged(value: any): Array<styleProperty.KeyValuePair<styleProperty.Property, any>> {
var thickness = parseThickness(value);
var array = new Array<styleProperty.KeyValuePair<styleProperty.Property, any>>();
array.push({ property: marginTopProperty, value: thickness.top });
array.push({ property: marginRightProperty, value: thickness.right });
array.push({ property: marginBottomProperty, value: thickness.bottom });
array.push({ property: marginLeftProperty, value: thickness.left });
return array;
}
function onFontChanged(value: any): Array<styleProperty.KeyValuePair<styleProperty.Property, any>> {
var newFont = font.Font.parse(value);
var array = new Array<styleProperty.KeyValuePair<styleProperty.Property, any>>();
array.push({ property: fontFamilyProperty, value: newFont.fontFamily });
array.push({ property: fontStyleProperty, value: newFont.fontStyle });
array.push({ property: fontWeightProperty, value: newFont.fontWeight });
array.push({ property: fontSizeProperty, value: newFont.fontSize });
return array;
}
// register default shorthand callbacks.
styleProperty.registerShorthandCallback("font", onFontChanged);
styleProperty.registerShorthandCallback("margin", onMarginChanged);
styleProperty.registerShorthandCallback("padding", onPaddingChanged);
// register default stylers once all properties are defined.
stylers._registerDefaultStylers();

View File

@@ -1,6 +1,5 @@
import types = require("utils/types");
import view = require("ui/core/view");
import constants = require("utils/android_constants");
import style = require("ui/styling/style");
import definition = require("ui/styling");
import stylersCommon = require("ui/styling/stylers-common");
@@ -9,39 +8,36 @@ import utils = require("utils/utils");
import styleModule = require("ui/styling/style");
import font = require("ui/styling/font");
import background = require("ui/styling/background");
var btn;
global.moduleMerge(stylersCommon, exports);
var _defaultBackgrounds = new Map<string, android.graphics.drawable.Drawable>();
function onBackgroundOrBorderPropertyChanged(v: view.View) {
if (!v._nativeView) {
var nativeView = <android.view.View>v._nativeView;
if (!nativeView) {
return;
}
var backgroundValue = <background.Background>v.style._getValue(styleModule.backgroundInternalProperty);
var borderWidth = v.borderWidth;
if (v.borderWidth !== 0 || v.borderRadius !== 0 || !backgroundValue.isEmpty()) {
var nativeView = <android.view.View>v._nativeView;
var bkg = <background.ad.BorderDrawable>nativeView.getBackground();
if (!(bkg instanceof background.ad.BorderDrawable)) {
bkg = new background.ad.BorderDrawable();
let viewClass = types.getClass(v);
if (!_defaultBackgrounds.has(viewClass)) {
if (!btn) {
btn = require("ui/button");
}
if (!(v instanceof btn.Button) && !_defaultBackgrounds.has(viewClass)) {
_defaultBackgrounds.set(viewClass, nativeView.getBackground());
}
nativeView.setBackground(bkg);
}
var density = utils.layout.getDisplayDensity();
nativeView.setPadding(
(v.borderWidth + v.style.paddingLeft) * density,
(v.borderWidth + v.style.paddingTop) * density,
(v.borderWidth + v.style.paddingRight) * density,
(v.borderWidth + v.style.paddingBottom) * density
);
bkg.borderWidth = v.borderWidth;
bkg.cornerRadius = v.borderRadius;
bkg.borderColor = v.borderColor ? v.borderColor.android : android.graphics.Color.TRANSPARENT;
@@ -49,11 +45,25 @@ function onBackgroundOrBorderPropertyChanged(v: view.View) {
}
else {
// reset the value with the default native value
let viewClass = types.getClass(v);
if (_defaultBackgrounds.has(viewClass)) {
v._nativeView.setBackgroundDrawable(_defaultBackgrounds.get(viewClass));
if (v instanceof btn.Button) {
var nativeButton = new android.widget.Button(nativeView.getContext());
nativeView.setBackground(nativeButton.getBackground());
}
else {
let viewClass = types.getClass(v);
if (_defaultBackgrounds.has(viewClass)) {
nativeView.setBackground(_defaultBackgrounds.get(viewClass));
}
}
}
var density = utils.layout.getDisplayDensity();
nativeView.setPadding(
(borderWidth + v.style.paddingLeft) * density,
(borderWidth + v.style.paddingTop) * density,
(borderWidth + v.style.paddingRight) * density,
(borderWidth + v.style.paddingBottom) * density
);
}
export class DefaultStyler implements definition.stylers.Styler {
@@ -206,7 +216,7 @@ export class DefaultStyler implements definition.stylers.Styler {
nativeView.setLayoutParams(lp);
}
private static setPaddingProperty(view: view.View, newValue: any) {
private static setPaddingProperty(view: view.View, newValue: style.Thickness) {
var density = utils.layout.getDisplayDensity();
var left = (newValue.left + view.borderWidth) * density;
var top = (newValue.top + view.borderWidth) * density;
@@ -215,12 +225,12 @@ export class DefaultStyler implements definition.stylers.Styler {
(<android.view.View>view._nativeView).setPadding(left, top, right, bottom);
}
private static resetPaddingProperty(view: view.View, nativeValue: any) {
private static resetPaddingProperty(view: view.View, nativeValue: style.Thickness) {
var density = utils.layout.getDisplayDensity();
var left = view.borderWidth * density;
var top = view.borderWidth * density;
var right = view.borderWidth * density;
var bottom = view.borderWidth * density;
var left = (nativeValue.left + view.borderWidth) * density;
var top = (nativeValue.top + view.borderWidth) * density;
var right = (nativeValue.right + view.borderWidth) * density;
var bottom = (nativeValue.bottom + view.borderWidth) * density;
(<android.view.View>view._nativeView).setPadding(left, top, right, bottom);
}
@@ -470,20 +480,27 @@ export class SegmentedBarStyler implements definition.stylers.Styler {
}
}
private static resetColorProperty(view: view.View, nativeValue: any) {
private static resetColorProperty(view: view.View, nativeValue: number) {
var tabHost = <android.widget.TabHost>view._nativeView;
for (var tabIndex = 0; tabIndex < tabHost.getTabWidget().getTabCount(); tabIndex++) {
var tab = <android.view.ViewGroup>tabHost.getTabWidget().getChildTabViewAt(tabIndex);
var t = <android.widget.TextView>tab.getChildAt(1);
t.setTextColor(constants.btn_default);
t.setTextColor(nativeValue);
}
}
private static getColorProperty(view: view.View): number {
var tabHost = <android.widget.TabHost>view._nativeView;
var textView = new android.widget.TextView(tabHost.getContext());
return textView.getCurrentTextColor();
}
public static registerHandlers() {
style.registerHandler(style.colorProperty, new stylersCommon.StylePropertyChangedHandler(
SegmentedBarStyler.setColorProperty,
SegmentedBarStyler.resetColorProperty), "SegmentedBar");
SegmentedBarStyler.resetColorProperty,
SegmentedBarStyler.getColorProperty), "SegmentedBar");
}
}

View File

@@ -1,9 +0,0 @@
export var btn_default = 0x01080004;
export var state_first = 0x010100a4;
export var state_enabled = 0x0101009e;
export var state_pressed = 0x010100a7;
export var state_selected = 0x010100a1;
export var state_single = 0x010100a3;
export var state_hovered = 0x01010367;
export var state_focused = 0x0101009c;

View File

@@ -1,9 +1,9 @@
export function isString(value: any): boolean {
return typeof value === "string";
return typeof value === "string" || value instanceof String;
}
export function isNumber(value: any): boolean {
return typeof value === "number";
return typeof value === "number" || value instanceof Number;
}
export function isFunction(value: any): boolean {