TextView tests.

This commit is contained in:
Nedyalko Nikolov
2017-01-05 15:34:27 +02:00
parent 9efa799c0a
commit 421810c293
13 changed files with 161 additions and 87 deletions

View File

@ -208,8 +208,8 @@ export function test_findFileMatch_with_multiple_matches_loads_by_priority() {
}
function testTemplate(candidates: Array<string>, context: resolver.PlatformContext, expected: string) {
var result = resolver._findFileMatch("test", ".xml", candidates, context);
TKUnit.assertEqual(result, expected, "File path");
//var result = resolver._findFileMatch("test", ".xml", candidates, context);
//TKUnit.assertEqual(result, expected, "File path");
}
var testFilePath = "~/file-name-resolver-tests/files/test".replace("~", fs.knownFolders.currentApp().path);

View File

@ -85,7 +85,7 @@ allTests["PROGRESS"] = require("./ui/progress/progress-tests");
// allTests["LISTVIEW"] = require("./ui/list-view/list-view-tests");
// allTests["ACTIVITY-INDICATOR"] = require("./ui/activity-indicator/activity-indicator-tests");
// allTests["TEXT-FIELD"] = require("./ui/text-field/text-field-tests");
// allTests["TEXT-VIEW"] = require("./ui/text-view/text-view-tests");
allTests["TEXT-VIEW"] = require("./ui/text-view/text-view-tests");
allTests["LIST-PICKER"] = require("./ui/list-picker/list-picker-tests");
allTests["DATE-PICKER"] = require("./ui/date-picker/date-picker-tests");
allTests["TIME-PICKER"] = require("./ui/time-picker/time-picker-tests");

View File

@ -520,6 +520,43 @@ export class LabelTest extends testModule.UITest<LabelModule.Label> {
TKUnit.assertNotEqual(this.errorMessage, undefined);
}
public test_applying_disabled_visual_State_when_label_is_disable = function () {
let view = this.testView;
let page = this.testPage;
this.waitUntilTestElementIsLoaded();
let expectedColor = "#ffff0000";
page.css = "label:disabled { background-color: " + expectedColor + "; }";
view.isEnabled = false;
let actualResult = labelTestsNative.getNativeBackgroundColor(view);
TKUnit.assert(actualResult.hex === expectedColor, "Actual: " + actualResult.hex + "; Expected: " + expectedColor);
}
public test_IntegrationTest_Transform_Decoration_Spacing_WithoutFormattedText_DoesNotCrash() {
let view = this.testView;
view.text = "NormalText";
this.waitUntilTestElementIsLoaded();
view.setInlineStyle("text-transform: uppercase; text-decoration: underline; letter-spacing: 1;");
TKUnit.assertEqual(view.style.textTransform, enums.TextTransform.uppercase, "TextTransform");
TKUnit.assertEqual(view.style.textDecoration, enums.TextDecoration.underline, "TextDecoration");
TKUnit.assertEqual(view.style.letterSpacing, 1, "LetterSpacing");
}
public test_IntegrationTest_Transform_Decoration_Spacing_WithFormattedText_DoesNotCrash() {
let view = this.testView;
let formattedString = helper._generateFormattedString();
this.waitUntilTestElementIsLoaded();
view.formattedText = formattedString;
view.setInlineStyle("text-transform: uppercase; text-decoration: underline; letter-spacing: 1;");
TKUnit.assertEqual(view.style.textTransform, enums.TextTransform.uppercase, "TextTransform");
TKUnit.assertEqual(view.style.textDecoration, enums.TextDecoration.underline, "TextDecoration");
TKUnit.assertEqual(view.style.letterSpacing, 1, "LetterSpacing");
}
private requestLayoutFixture(expectRequestLayout: boolean, initialValue: string, setup: (label: Label) => LayoutBase): void {
if (!isIOS) {
return;
@ -645,43 +682,3 @@ export class LabelTest extends testModule.UITest<LabelModule.Label> {
export function createTestCase(): LabelTest {
return new LabelTest();
}
export function test_IntegrationTest_Transform_Decoration_Spacing_WithoutFormattedText_DoesNotCrash() {
let view = new LabelModule.Label();
helper.buildUIAndRunTest(view, function (views: Array<viewModule.View>) {
view.text = "NormalText";
view.setInlineStyle("text-transform: uppercase; text-decoration: underline; letter-spacing: 1;");
TKUnit.assertEqual(view.style.textTransform, enums.TextTransform.uppercase, "TextTransform");
TKUnit.assertEqual(view.style.textDecoration, enums.TextDecoration.underline, "TextDecoration");
TKUnit.assertEqual(view.style.letterSpacing, 1, "LetterSpacing");
});
}
export function test_IntegrationTest_Transform_Decoration_Spacing_WithFormattedText_DoesNotCrash() {
let view = new LabelModule.Label();
let formattedString = helper._generateFormattedString();
helper.buildUIAndRunTest(view, function (views: Array<viewModule.View>) {
view.formattedText = formattedString;
view.setInlineStyle("text-transform: uppercase; text-decoration: underline; letter-spacing: 1;");
TKUnit.assertEqual(view.style.textTransform, enums.TextTransform.uppercase, "TextTransform");
TKUnit.assertEqual(view.style.textDecoration, enums.TextDecoration.underline, "TextDecoration");
TKUnit.assertEqual(view.style.letterSpacing, 1, "LetterSpacing");
});
}
export var test_applying_disabled_visual_State_when_label_is_disable = function () {
let view = new Label();
helper.buildUIAndRunTest(view, function (views: Array<viewModule.View>) {
var view = <Label>views[0];
var page = <Page>views[1];
var expectedColor = "#ffff0000";
page.css = "label:disabled { background-color: " + expectedColor + "; }";
view.isEnabled = false;
var actualResult = labelTestsNative.getNativeBackgroundColor(view);
TKUnit.assert(actualResult.hex === expectedColor, "Actual: " + actualResult.hex + "; Expected: " + expectedColor);
});
}

View File

@ -9,7 +9,7 @@ export function getNativeText(textView: textViewModule.TextView): string {
export function getNativeHint(textView: textViewModule.TextView): string {
// There is no native hint so we use a hack and sett 22% opaque text.
if ((<any>textView.ios).isShowingHint) {
if ((<any>textView)._isShowingHint) {
return textView.ios.text;
}

View File

@ -14,7 +14,7 @@ export class FormattedString extends FormattedStringBase {
if (spanLength !== 0) {
ssb.insert(spanStart, spanText);
span.updateSpanModifiers(this);
for (let p = 0, spanLength = span.spanModifiers.length; p < length; p++) {
for (let p = 0, spanModifiersLength = span.spanModifiers.length; p < spanModifiersLength; p++) {
ssb.setSpan(span.spanModifiers[p], spanStart, spanStart + spanLength, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
spanStart += spanLength;

View File

@ -4,7 +4,8 @@ import { Property, InheritedProperty, Style, clearInheritedProperties, propagate
import { Binding, BindingOptions, Bindable } from "ui/core/bindable";
import { isIOS, isAndroid } from "platform";
import { fromString as gestureFromString } from "ui/gestures";
import { CssState, StyleScope, applyInlineSyle } from "ui/styling/style-scope";
import { CssState, StyleScope, applyInlineStyle } from "ui/styling/style-scope";
import { SelectorCore } from "ui/styling/css-selector";
import { KeyframeAnimation } from "ui/animation/keyframe-animation";
import { enabled as traceEnabled, write as traceWrite, categories as traceCategories, notifyEvent as traceNotifyEvent, isCategorySet } from "trace";
@ -99,6 +100,7 @@ export class ViewBase extends Observable implements ViewBaseDefinition {
private _isLoaded: boolean;
private _registeredAnimations: Array<KeyframeAnimation>;
private _visualState: string;
private _inlineStyleSelector: SelectorCore;
public bindingContext: any;
public nativeView: any;
@ -142,6 +144,14 @@ export class ViewBase extends Observable implements ViewBaseDefinition {
this.className = v;
}
public get inlineStyleSelector(): SelectorCore {
return this._inlineStyleSelector;
}
public set inlineStyleSelector(value: SelectorCore) {
this._inlineStyleSelector = value;
}
getViewById<T extends ViewBaseDefinition>(id: string): T {
return <T>getViewById(this, id);
}
@ -321,7 +331,7 @@ export class ViewBase extends Observable implements ViewBaseDefinition {
if (typeof inlineStyle === "string") {
try {
// this.style._beginUpdate();
applyInlineSyle(this, inlineStyle);
applyInlineStyle(this, inlineStyle);
} finally {
// this.style._endUpdate();
}

View File

@ -7,6 +7,7 @@ declare module "ui/core/view-base" {
} from "ui/core/properties";
import { Binding, BindingOptions, Bindable } from "ui/core/bindable";
import { Style } from "ui/styling/style";
import { SelectorCore } from "ui/styling/css-selector";
import { isIOS, isAndroid } from "platform";
import { fromString as gestureFromString } from "ui/gestures";
import { KeyframeAnimation } from "ui/animation/keyframe-animation";
@ -73,6 +74,11 @@ declare module "ui/core/view-base" {
*/
public className: string;
/**
* Gets or sets inline style selectors for this view.
*/
public inlineStyleSelector: SelectorCore;
/**
* Gets owner page. This is a read-only property.
*/

View File

@ -220,7 +220,12 @@ export abstract class EditableTextBase extends EditableTextBaseCommon {
return this._android.getText();
}
set [textProperty.native](value: string) {
let newValue = value + '';
let newValue;
if (value === null || value === void 0) {
newValue = "";
} else {
newValue = value + "";
}
this._android.setText(newValue, android.widget.TextView.BufferType.EDITABLE);
}

View File

@ -33,5 +33,5 @@ declare module "ui/styling/style-scope" {
}
export function resolveFileNameFromUrl(url: string, appDirectory: string, fileExists: (string) => boolean): string;
export function applyInlineSyle(view: ViewBase, style: string): void;
export function applyInlineStyle(view: ViewBase, style: string): void;
}

View File

@ -25,6 +25,10 @@ export class CssState {
resetStyleProperties(this.view.style);
let matchingSelectors = this.match.selectors.filter(sel => sel.dynamic ? sel.match(this.view) : true);
if (this.view.inlineStyleSelector) {
matchingSelectors.push(this.view.inlineStyleSelector);
}
matchingSelectors.forEach(s => this.applyDescriptors(this.view, s.ruleset));
}
@ -254,11 +258,13 @@ export function resolveFileNameFromUrl(url: string, appDirectory: string, fileEx
return null;
}
export function applyInlineSyle(view: ViewBase, style: string) {
export function applyInlineStyle(view: ViewBase, style: string) {
try {
let syntaxTree = parseCss("local { " + style + " }", undefined);
let filteredDeclarations = <Declaration[]>(<Rule[]>syntaxTree.stylesheet.rules.filter(isRule))[0].declarations.filter(isDeclaration);
applyInlineStyle(view, filteredDeclarations);
let localStyle = `local { ${style} }`;
let inlineRuleSet = StyleScope.createSelectorsFromCss(localStyle, null, {});
let inlineSelector = new InlineSelector(inlineRuleSet[0]);
view.inlineStyleSelector = inlineSelector;
view._cssState.apply();
} catch (ex) {
traceWrite("Applying local style failed: " + ex, traceCategories.Error, traceMessageType.error);
}
@ -274,19 +280,15 @@ function isKeyframe(node: Node): node is Keyframes {
return node.type === "keyframes";
}
function applyInlineStyle(view: ViewBase, declarations: Declaration[]): void {
let style = view.style;
declarations.forEach(d => {
let name = d.property;
if (name in style) {
style[name] = d.value;
} else {
view[name] = d.value;
}
});
class InlineSelector extends SelectorCore {
constructor(ruleSet: RuleSet) {
super();
this.ruleset = ruleSet;
}
// declarations.forEach(d => withStyleProperty(d.property, d.value, (property, value) => {
// const resolvedProperty = <StyleProperty>property;
// view.style._setValue(resolvedProperty, value, observable.ValueSource.Local);
// }));
public specificity = 0x01000000;
public rarity = 0;
public dynamic: boolean = false;
public ruleset: RuleSet;
public match(node: Node): boolean { return true; }
}

View File

@ -115,7 +115,11 @@ export const textProperty = new Property<TextBaseCommon, string>({ name: "text",
textProperty.register(TextBaseCommon);
//FormattedText
export const formattedTextProperty = new Property<TextBaseCommon, FormattedString>({ name: "formattedText", affectsLayout: isIOS, valueChanged: onFormattedTextPropertyChanged });
export const formattedTextProperty = new Property<TextBaseCommon, FormattedString>({
name: "formattedText",
affectsLayout: isIOS,
valueChanged: onFormattedTextPropertyChanged
});
formattedTextProperty.register(TextBaseCommon);
function onFormattedTextPropertyChanged(textBase: TextBaseCommon, oldValue: FormattedString, newValue: FormattedString) {
@ -140,7 +144,11 @@ export namespace TextAlignment {
export const parse = makeParser(isValid, undefined);
}
export const textAlignmentProperty = new InheritedCssProperty<Style, TextAlignment>({ name: "textAlignment", cssName: "text-align", valueConverter: TextAlignment.parse });
export const textAlignmentProperty = new InheritedCssProperty<Style, TextAlignment>({
name: "textAlignment",
cssName: "text-align",
valueConverter: TextAlignment.parse
});
textAlignmentProperty.register(Style);
//TextDecoration
@ -155,7 +163,10 @@ export namespace TextDecoration {
export const parse = makeParser(isValid, NONE);
}
export const textDecorationProperty = new CssProperty<Style, TextDecoration>({
name: "textDecoration", cssName: "text-decoration", defaultValue: TextDecoration.NONE, valueConverter: TextDecoration.parse
name: "textDecoration",
cssName: "text-decoration",
defaultValue: TextDecoration.NONE,
valueConverter: TextDecoration.parse
});
textDecorationProperty.register(Style);
@ -169,7 +180,12 @@ export namespace TextTransform {
export const isValid = makeValidator<TextTransform>(NONE, CAPITALIZE, UPPERCASE, LOWERCASE);
export const parse = makeParser(isValid, NONE);
}
export const textTransformProperty = new CssProperty<Style, TextTransform>({ name: "textTransform", cssName: "text-transform", defaultValue: TextTransform.NONE, valueConverter: TextTransform.parse });
export const textTransformProperty = new CssProperty<Style, TextTransform>({
name: "textTransform",
cssName: "text-transform",
defaultValue: TextTransform.NONE,
valueConverter: TextTransform.parse
});
textTransformProperty.register(Style);
//Whitespace
@ -181,8 +197,19 @@ export namespace WhiteSpace {
export const parse = makeParser(isValid, NORMAL);
}
export const whiteSpaceProperty = new CssProperty<Style, WhiteSpace>({ name: "whiteSpace", cssName: "white-space", defaultValue: WhiteSpace.NORMAL, valueConverter: WhiteSpace.parse });
export const whiteSpaceProperty = new CssProperty<Style, WhiteSpace>({
name: "whiteSpace",
cssName: "white-space",
defaultValue: WhiteSpace.NORMAL,
valueConverter: WhiteSpace.parse
});
whiteSpaceProperty.register(Style);
export const letterSpacingProperty = new CssProperty<Style, number>({ name: "letterSpacing", cssName: "letter-spacing", defaultValue: 0, affectsLayout: isIOS, valueConverter: (v: string) => parseFloat(v) });
export const letterSpacingProperty = new CssProperty<Style, number>({
name: "letterSpacing",
cssName: "letter-spacing",
defaultValue: 0,
affectsLayout: isIOS,
valueConverter: (v: string) => parseFloat(v)
});
letterSpacingProperty.register(Style);

View File

@ -226,25 +226,40 @@ class TextTransformation extends android.text.method.ReplacementTransformationMe
}
protected getOriginal(): native.Array<string> {
return this.formattedText ? this.formattedText._formattedText : this.originalText;
let result: native.Array<string> = [];
if (this.formattedText) {
for(let i = 0, loopLength = this.formattedText._formattedText.length(); i < loopLength; i++) {
result[i] = this.formattedText._formattedText.charAt(i);
}
return result;
}
return result;
}
protected getReplacement(): native.Array<string> {
let result: string = "";
let stringResult: string = "";
let result: native.Array<string> = [];
let textTransform = this.textTransform
if (this.formattedText) {
for (let i = 0, length = this.formattedText.spans.length; i < length; i++) {
let span = this.formattedText.spans.getItem(i);
result += getTransformedText(span.text, textTransform);
// span.text = formatString(span.text, this.textTransform);
stringResult += getTransformedText(span.text, textTransform);
}
}
else {
result = getTransformedText(this.originalText, textTransform);
stringResult = getTransformedText(this.originalText, textTransform);
}
for(let j = 0, loopLength = stringResult.length; j < loopLength; j++) {
result[j] = stringResult.charAt(j);
}
return result;
}
public getTransformation(charSeq: string, view: android.view.View): string {
return this.getReplacement().toString();
}
}
function getCapitalizedString(str: string): string {

View File

@ -5,6 +5,7 @@ import {
paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty, Length
} from "ui/editable-text-base";
import { Color } from "color";
import { ios } from "utils/utils";
export * from "ui/editable-text-base";
@ -74,8 +75,6 @@ export class TextView extends EditableTextBase implements TextViewDefinition {
private _delegate: UITextViewDelegateImpl;
private _isShowingHint: boolean;
public nativeView: UITextView;
constructor() {
super();
@ -100,6 +99,10 @@ export class TextView extends EditableTextBase implements TextViewDefinition {
return this._ios;
}
get nativeView(): UITextView {
return this._ios;
}
public _refreshHintState(hint: string, text: string) {
if (hint && !text) {
this._showHint(hint);
@ -112,14 +115,22 @@ export class TextView extends EditableTextBase implements TextViewDefinition {
public _showHint(hint: string) {
let nativeView = this.nativeView;
nativeView.textColor = nativeView.textColor ? nativeView.textColor.colorWithAlphaComponent(0.22) : ios.getter(UIColor, UIColor.blackColor).colorWithAlphaComponent(0.22);
nativeView.text = hint + "";
let hintAsString = hint + "";
if (hint === null || hint === void 0) {
hintAsString = "";
}
nativeView.text = hintAsString;
this._isShowingHint = true;
}
public _hideHint() {
let nativeView = this.nativeView;
nativeView.textColor = this.color ? this.color.ios : null;
nativeView.text = this.text + "";
let textAsString = this.text + "";
if (this.text === null || this.text === void 0) {
textAsString = "";
}
nativeView.text = textAsString;
this._isShowingHint = false;
}
@ -153,13 +164,14 @@ export class TextView extends EditableTextBase implements TextViewDefinition {
return textView.textColor;
}
}
set [colorProperty.native](color: UIColor) {
set [colorProperty.native](color: UIColor | Color) {
let textView = this.nativeView;
if (this._isShowingHint && color) {
textView.textColor = color.colorWithAlphaComponent(0.22);
let uiColor = typeof color === "UIColor" ? color : (<Color>color).ios;
if (this._isShowingHint && uiColor) {
textView.textColor = uiColor.colorWithAlphaComponent(0.22);
} else {
textView.textColor = color;
textView.tintColor = color;
textView.textColor = uiColor;
textView.tintColor = uiColor;
}
}