diff --git a/tests/app/ui/segmented-bar/segmented-bar-tests-native.android.ts b/tests/app/ui/segmented-bar/segmented-bar-tests-native.android.ts index d9055d5b0..8ad54cca0 100644 --- a/tests/app/ui/segmented-bar/segmented-bar-tests-native.android.ts +++ b/tests/app/ui/segmented-bar/segmented-bar-tests-native.android.ts @@ -14,7 +14,7 @@ export function checkNativeItemsTextColor(bar: segmentedBarModule.SegmentedBar): // isValid = bar.color && bar.color.android === t.getCurrentTextColor(); // } - for(let i = 0, itemsLength = bar.items.length; i < itemsLength; i++) { + for (let i = 0, itemsLength = bar.items.length; i < itemsLength; i++) { let textView = bar.items[0].nativeView; isValid = bar.color && bar.color.android === textView.getCurrentTextColor(); } diff --git a/tests/app/ui/segmented-bar/segmented-bar-tests.ts b/tests/app/ui/segmented-bar/segmented-bar-tests.ts index ba5d73559..747bd78f7 100644 --- a/tests/app/ui/segmented-bar/segmented-bar-tests.ts +++ b/tests/app/ui/segmented-bar/segmented-bar-tests.ts @@ -1,10 +1,10 @@ import * as TKUnit from "../../TKUnit"; import * as segmentedBarTestsNative from "./segmented-bar-tests-native"; -import {buildUIAndRunTest} from "../helper"; -import {View} from "ui/core/view"; -import {BindingOptions} from "ui/core/bindable"; -import {Observable} from "data/observable"; -import {Color} from "color"; +import { buildUIAndRunTest } from "../helper"; +import { View } from "ui/core/view"; +import { BindingOptions } from "ui/core/bindable"; +import { Observable } from "data/observable"; +import { Color } from "color"; // >> article-require-segmentedbar-module import * as segmentedBarModule from "ui/segmented-bar"; @@ -77,7 +77,7 @@ export var testWhenItemsAreBoundTheTextColorIsPreserved = function () { } segmentedBar.bind(options, model); - + TKUnit.assert(segmentedBarTestsNative.checkNativeItemsTextColor(segmentedBar), "Items text color not preserved" + "; Expected: " + segmentedBar.color); }); } @@ -181,13 +181,13 @@ export var testSelectedIndexChangedIsReisedCorrectlyIfSelectedIndexIsSet = funct var newIndex; var segmentedBar = _createSegmentedBar(); - segmentedBar.on(segmentedBarModule.SegmentedBar.selectedIndexChangedEvent, (args : segmentedBarModule.SelectedIndexChangedEventData) => { + segmentedBar.on(segmentedBarModule.SegmentedBar.selectedIndexChangedEvent, (args: segmentedBarModule.SelectedIndexChangedEventData) => { oldIndex = args.oldIndex; newIndex = args.newIndex; }); segmentedBar.items = _createItems(10); - + buildUIAndRunTest(segmentedBar, function (views: Array) { var segmentedBar = views[0]; @@ -262,7 +262,7 @@ export function test_SettingNumberAsTitleFromXML_DoesNotThrow() { let item = new segmentedBarModule.SegmentedBarItem(); (item).title = 1; segmentedBar.items = [item]; - + buildUIAndRunTest(segmentedBar, function (views: Array) { TKUnit.assertEqual(item.title, "1"); }); diff --git a/tns-core-modules/ui/builder/component-builder.ts b/tns-core-modules/ui/builder/component-builder.ts index 04309a8d5..7215af8c7 100644 --- a/tns-core-modules/ui/builder/component-builder.ts +++ b/tns-core-modules/ui/builder/component-builder.ts @@ -126,7 +126,7 @@ export function getComponentModule(elementName: string, namespace: string, attri throw new Error(`Css file with path "${cssFilePath}" cannot be found!`); } } else { - throw new Error("Css file atribute is valid only for pages!"); + throw new Error("Css file attribute is valid only for pages!"); } } } diff --git a/tns-core-modules/ui/core/properties.ts b/tns-core-modules/ui/core/properties.ts index f408b153b..ab899e770 100644 --- a/tns-core-modules/ui/core/properties.ts +++ b/tns-core-modules/ui/core/properties.ts @@ -28,7 +28,7 @@ export function _isSet(cssProperty: CssProperty, instance: Style): boo export function _printUnregisteredProperties(): void { print(symbolPropertyMap); - print(cssSymbolPropertyMap) + print(cssSymbolPropertyMap); } const enum ValueSource { @@ -132,11 +132,11 @@ export class Property implements PropertyDescriptor, defi this.requestLayout(); } } - } + }; this.get = function (this: T): U { return key in this ? this[key] : defaultValue; - } + }; this.nativeValueChange = function (owner: T, value: U): void { const currentValue = key in owner ? owner[key] : defaultValue; @@ -160,7 +160,7 @@ export class Property implements PropertyDescriptor, defi owner.requestLayout(); } } - } + }; symbolPropertyMap[key] = this; } @@ -219,7 +219,7 @@ export class CoercibleProperty implements PropertyDescrip const originalValue: U = coerceKey in target ? target[coerceKey] : defaultValue; // need that to make coercing but also fire change events this.set.call(target, originalValue); - } + }; this.set = function (this: T, value: U): void { const reset = value === unsetValue; @@ -283,11 +283,11 @@ export class CoercibleProperty implements PropertyDescrip this.requestLayout(); } } - } + }; this.get = function (): U { return key in this ? this[key] : defaultValue; - } + }; this.nativeValueChange = function (owner: T, value: U): void { const currentValue = key in owner ? owner[key] : defaultValue; @@ -312,7 +312,7 @@ export class CoercibleProperty implements PropertyDescrip owner.requestLayout(); } } - } + }; symbolPropertyMap[key] = this; } @@ -387,7 +387,7 @@ export class InheritedProperty extends Property imp return true; }); } - } + }; const setInheritedValue = setFunc(ValueSource.Inherited); this.setInheritedValue = setInheritedValue; @@ -403,6 +403,7 @@ export class CssProperty implements definitions.CssProperty< public readonly name: string; public readonly cssName: string; + public readonly cssLocalName: string; protected readonly cssValueDescriptor: PropertyDescriptor; protected readonly localValueDescriptor: PropertyDescriptor; @@ -417,8 +418,8 @@ export class CssProperty implements definitions.CssProperty< const name = options.name; this.name = name; - const cssName = `css-${options.cssName}`; - this.cssName = cssName; + this.cssName = `css-${options.cssName}`; + this.cssLocalName = options.cssName; const key = Symbol(name + ":propertyKey"); this.key = key; @@ -593,6 +594,9 @@ export class CssProperty implements definitions.CssProperty< this.registered = true; Object.defineProperty(cls.prototype, this.name, this.localValueDescriptor); Object.defineProperty(cls.prototype, this.cssName, this.cssValueDescriptor); + if (this.cssLocalName !== this.cssName) { + Object.defineProperty(cls.prototype, this.cssLocalName, this.localValueDescriptor); + } } } @@ -634,7 +638,7 @@ export class InheritedCssProperty extends CssProperty if (reset) { // If unsetValue - we want to reset this property. let parent = view.parent; - let style = parent ? parent.style : null + let style = parent ? parent.style : null; // If we have parent and it has non-default value we use as our inherited value. if (style && style[sourceKey] > ValueSource.Default) { newValue = style[name]; @@ -712,7 +716,7 @@ export class InheritedCssProperty extends CssProperty return true; }); } - } + }; const setDefaultFunc = setFunc(ValueSource.Default); const setInheritedFunc = setFunc(ValueSource.Inherited); @@ -731,6 +735,7 @@ export class ShorthandProperty implements definitions.Shorth public readonly key: symbol; public readonly name: string; public readonly cssName: string; + public readonly cssLocalName: string; protected readonly cssValueDescriptor: PropertyDescriptor; protected readonly localValueDescriptor: PropertyDescriptor; @@ -739,14 +744,13 @@ export class ShorthandProperty implements definitions.Shorth public readonly sourceKey: symbol; constructor(options: definitions.ShorthandPropertyOptions

) { - const name = options.name; - this.name = name; + this.name = options.name; - const key = Symbol(name + ":propertyKey"); + const key = Symbol(this.name + ":propertyKey"); this.key = key; - const cssName = `css-${options.cssName}`; - this.cssName = cssName; + this.cssName = `css-${options.cssName}`; + this.cssLocalName = `${options.cssName}`; const converter = options.converter; @@ -792,6 +796,9 @@ export class ShorthandProperty implements definitions.Shorth this.registered = true; Object.defineProperty(cls.prototype, this.name, this.localValueDescriptor); Object.defineProperty(cls.prototype, this.cssName, this.cssValueDescriptor); + if (this.cssLocalName !== this.cssName) { + Object.defineProperty(cls.prototype, this.cssLocalName, this.localValueDescriptor); + } } } @@ -958,5 +965,5 @@ export function makeParser(isValid: (value: any) => boolean): (value: any) => } else { throw new Error("Invalid value: " + value); } - } + }; } \ No newline at end of file diff --git a/tns-core-modules/ui/segmented-bar/segmented-bar-common.ts b/tns-core-modules/ui/segmented-bar/segmented-bar-common.ts index b426e38a6..af399f4a5 100644 --- a/tns-core-modules/ui/segmented-bar/segmented-bar-common.ts +++ b/tns-core-modules/ui/segmented-bar/segmented-bar-common.ts @@ -1,7 +1,7 @@ import { SegmentedBar as SegmentedBarDefinition, SegmentedBarItem as SegmentedBarItemDefinition, SelectedIndexChangedEventData } from "ui/segmented-bar"; import { ViewBase, View, AddChildFromBuilder, AddArrayFromBuilder, - Property, CoercibleProperty, CssProperty, Color, Style + Property, CoercibleProperty, InheritedCssProperty, Color, Style } from "ui/core/view"; export * from "ui/core/view"; @@ -45,7 +45,9 @@ export abstract class SegmentedBarBase extends View implements SegmentedBarDefin if (!this.items) { this.items = new Array(); } - this.items.push(value); + let item = value; + this.items.push(item); + this._addView(item); selectedIndexProperty.coerce(this); } } @@ -111,5 +113,5 @@ export const itemsProperty = new Property({ name: "selectedBackgroundColor", cssName: "selected-background-color", equalityComparer: Color.equals, valueConverter: (v) => new Color(v) }) +export const selectedBackgroundColorProperty = new InheritedCssProperty({ name: "selectedBackgroundColor", cssName: "selected-background-color", equalityComparer: Color.equals, valueConverter: (v) => new Color(v) }); selectedBackgroundColorProperty.register(Style); diff --git a/tns-core-modules/ui/segmented-bar/segmented-bar.android.ts b/tns-core-modules/ui/segmented-bar/segmented-bar.android.ts index aae5f6958..60359fda2 100644 --- a/tns-core-modules/ui/segmented-bar/segmented-bar.android.ts +++ b/tns-core-modules/ui/segmented-bar/segmented-bar.android.ts @@ -8,6 +8,7 @@ export * from "./segmented-bar-common"; const R_ID_TABS = 0x01020013; const R_ID_TABCONTENT = 0x01020011; const R_ATTR_STATE_SELECTED = 0x010100a1; +const TITLE_TEXT_VIEW_ID = 16908310; // http://developer.android.com/reference/android/R.id.html#title let apiLevel: number; // TODO: Move this into widgets. @@ -56,9 +57,13 @@ export class SegmentedBarItem extends SegmentedBarItemBase { return this._textView; } - public setNativeView(textView: android.widget.TextView): void { - this._textView = textView; - if (textView) { + public setupNativeView(tabIndex: number): void { + // TabHost.TabSpec.setIndicator DOES NOT WORK once the title has been set. + // http://stackoverflow.com/questions/2935781/modify-tab-indicator-dynamically-in-android + const titleTextView = this.parent.android.getTabWidget().getChildAt(tabIndex).findViewById(TITLE_TEXT_VIEW_ID); + + this._textView = titleTextView; + if (titleTextView) { applyNativeSetters(this); if (this.titleDirty) { this._update(); @@ -68,15 +73,6 @@ export class SegmentedBarItem extends SegmentedBarItemBase { private titleDirty: boolean; public _update(): void { - // if (this._parent && this._parent.android) { - // // TabHost.TabSpec.setIndicator DOES NOT WORK once the title has been set. - // // http://stackoverflow.com/questions/2935781/modify-tab-indicator-dynamically-in-android - // const tabIndex = this._parent.items.indexOf(this); - // const titleTextViewId = 16908310; // http://developer.android.com/reference/android/R.id.html#title - // const titleTextView = this._parent.android.getTabWidget().getChildAt(tabIndex).findViewById(titleTextViewId); - // titleTextView.setText(this.title || ""); - // } - const tv = this._textView; if (tv) { let title = this.title; @@ -168,15 +164,12 @@ class TabContentFactory extends java.lang.Object implements android.widget.TabHo let owner = this.owner.get(); if (owner) { let tv = new android.widget.TextView(owner._context); - let index = parseInt(tag); - // This is collapsed by default and made visibile + // This is collapsed by default and made visible // by android when TabItem becomes visible/selected. - // TODO: Try commenting visigility change. + // TODO: Try commenting visibility change. tv.setVisibility(android.view.View.GONE); tv.setMaxLines(1); tv.setEllipsize(android.text.TextUtils.TruncateAt.END); - - (owner.items[index]).setNativeView(tv); return tv; } else { throw new Error(`Invalid owner: ${this.owner}`); @@ -233,6 +226,7 @@ export class SegmentedBar extends SegmentedBarBase { let tabHost = this.android; this._addingTab = true; tabHost.addTab(tab); + tabItem.setupNativeView(index); this._addingTab = false; } diff --git a/tns-core-modules/ui/styling/style-scope.ts b/tns-core-modules/ui/styling/style-scope.ts index bcdcf410d..c6ee33697 100644 --- a/tns-core-modules/ui/styling/style-scope.ts +++ b/tns-core-modules/ui/styling/style-scope.ts @@ -8,7 +8,7 @@ import * as application from "application"; import * as kam from "ui/animation/keyframe-animation"; let keyframeAnimationModule: typeof kam; function ensureKeyframeAnimationModule() { - if (!keyframeAnimationModule){ + if (!keyframeAnimationModule) { keyframeAnimationModule = require("ui/animation/keyframe-animation"); } } @@ -16,7 +16,7 @@ function ensureKeyframeAnimationModule() { import * as capm from "./css-animation-parser"; let cssAnimationParserModule: typeof capm; function ensureCssAnimationParserModule() { - if (!cssAnimationParserModule){ + if (!cssAnimationParserModule) { cssAnimationParserModule = require("./css-animation-parser"); } } @@ -48,15 +48,16 @@ export class CssState { private applyDescriptors(view: ViewBase, ruleset: RuleSet): void { let style = view.style; ruleset.declarations.forEach(d => { - let name = `css-${d.property}`; - if (name in style) { - try { - style[name] = d.value; - } catch (e) { - traceWrite(`Failed to apply property [${d.property}] with value [${d.value}] to ${view}. ${e}`, traceCategories.Error, traceMessageType.error) + try { + // Use the "css-" prefixed name, so that CSS value source is set. + let cssPropName = `css-${d.property}`; + if (cssPropName in style) { + style[cssPropName] = d.value; + } else { + view[d.property] = d.value; } - } else { - view[d.property] = d.value; + } catch (e) { + traceWrite(`Failed to apply property [${d.property}] with value [${d.value}] to ${view}. ${e}`, traceCategories.Error, traceMessageType.error); } }); @@ -228,7 +229,7 @@ export class StyleScope { (nodes.filter(isKeyframe)).forEach(node => keyframes[node.name] = node); let rulesets = fromAstNodes(nodes); - if (rulesets && rulesets.length){ + if (rulesets && rulesets.length) { ensureCssAnimationParserModule(); rulesets.forEach(rule => rule[animationsSymbol] = cssAnimationParserModule.CssAnimationParser.keyframeAnimationsFromCSSDeclarations(rule.declarations)); } @@ -262,7 +263,7 @@ export class StyleScope { } } -export function resolveFileNameFromUrl(url: string, appDirectory: string, fileExists: (string) => boolean): string { +export function resolveFileNameFromUrl(url: string, appDirectory: string, fileExists: (name: string) => boolean): string { let fileName: string = typeof url === "string" ? url.trim() : ""; if (fileName.indexOf("~/") === 0) { @@ -282,21 +283,24 @@ export function resolveFileNameFromUrl(url: string, appDirectory: string, fileEx return null; } -export function applyInlineStyle(view: ViewBase, style: string) { - try { - let localStyle = `local { ${style} }`; - let inlineRuleSet = StyleScope.createSelectorsFromCss(localStyle, null, {}); - let inlineSelector = new InlineSelector(inlineRuleSet[0]); - view.inlineStyleSelector = inlineSelector; - if (view._cssState) { - view._cssState.apply(); - } else { - let styleScope = new StyleScope(); - styleScope.applySelectors(view); +export function applyInlineStyle(view: ViewBase, styleStr: string) { + let localStyle = `local { ${styleStr} }`; + let inlineRuleSet = StyleScope.createSelectorsFromCss(localStyle, null, {}); + const style = view.style; + + inlineRuleSet[0].declarations.forEach(d => { + // Use the actual property name so that a local value is set. + let name = d.property; + try { + if (name in style) { + style[name] = d.value; + } else { + view[name] = d.value; + } + } catch (e) { + traceWrite(`Failed to apply property [${d.property}] with value [${d.value}] to ${view}. ${e}`, traceCategories.Error, traceMessageType.error); } - } catch (ex) { - traceWrite("Applying local style failed: " + ex, traceCategories.Error, traceMessageType.error); - } + }); } function isKeyframe(node: Node): node is Keyframes {