mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Total TextBase refactoring + several bug fixes.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Button as ButtonDefinition } from "ui/button";
|
||||
import { TextBase } from "ui/text-base";
|
||||
import { TextBase, WhiteSpace } from "ui/text-base";
|
||||
|
||||
export * from "ui/text-base";
|
||||
|
||||
@@ -7,9 +7,9 @@ export abstract class ButtonBase extends TextBase implements ButtonDefinition {
|
||||
public static tapEvent = "tap";
|
||||
|
||||
get textWrap(): boolean {
|
||||
return this.style.whiteSpace === "normal";
|
||||
return this.style.whiteSpace === WhiteSpace.NORMAL;
|
||||
}
|
||||
set textWrap(value: boolean) {
|
||||
this.style.whiteSpace = value ? "normal" : "nowrap";
|
||||
this.style.whiteSpace = value ? WhiteSpace.NORMAL : WhiteSpace.NO_WRAP;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
ButtonBase, textProperty, formattedTextProperty, TouchGestureEventData, FormattedString, GestureTypes, TouchAction,
|
||||
PseudoClassHandler
|
||||
PseudoClassHandler, TextTransform
|
||||
} from "./button-common";
|
||||
|
||||
export * from "./button-common";
|
||||
@@ -23,7 +23,6 @@ class ClickListener extends java.lang.Object implements android.view.View.OnClic
|
||||
export class Button extends ButtonBase {
|
||||
_button: android.widget.Button;
|
||||
private _isPressed: boolean;
|
||||
private _transformationMethod;
|
||||
private _highlightedHandler: (args: TouchGestureEventData) => void;
|
||||
|
||||
get android(): android.widget.Button {
|
||||
@@ -36,22 +35,6 @@ export class Button extends ButtonBase {
|
||||
this._button.setOnClickListener(new ClickListener(weakRef));
|
||||
}
|
||||
|
||||
public _setFormattedTextPropertyToNative(value: FormattedString) {
|
||||
let newText = value ? value._formattedText : null;
|
||||
if (newText) {
|
||||
if (!this._transformationMethod) {
|
||||
this._transformationMethod = this.android.getTransformationMethod();
|
||||
}
|
||||
this.android.setTransformationMethod(null);
|
||||
} else {
|
||||
if (this._transformationMethod && !this.android.getTransformationMethod()) {
|
||||
this.android.setTransformationMethod(this._transformationMethod);
|
||||
}
|
||||
}
|
||||
|
||||
this._button.setText(newText);
|
||||
}
|
||||
|
||||
@PseudoClassHandler("normal", "highlighted", "pressed", "active")
|
||||
_updateHandler(subscribe: boolean) {
|
||||
if (subscribe) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import {
|
||||
View, ButtonBase, PseudoClassHandler, textProperty, formattedTextProperty, whiteSpaceProperty,
|
||||
borderTopWidthProperty, borderRightWidthProperty, borderBottomWidthProperty, borderLeftWidthProperty,
|
||||
paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty, Length
|
||||
paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty, Length, WhiteSpace
|
||||
} from "./button-common";
|
||||
|
||||
export * from "./button-common";
|
||||
@@ -42,18 +42,22 @@ export class Button extends ButtonBase {
|
||||
}
|
||||
}
|
||||
|
||||
get [whiteSpaceProperty.native](): "normal" | "nowrap" {
|
||||
return "normal";
|
||||
get [whiteSpaceProperty.native](): WhiteSpace {
|
||||
return WhiteSpace.NORMAL;
|
||||
}
|
||||
set [whiteSpaceProperty.native](value: "normal" | "nowrap") {
|
||||
set [whiteSpaceProperty.native](value: WhiteSpace) {
|
||||
let nativeView = this.nativeView.titleLabel;
|
||||
if (value === "normal") {
|
||||
switch(value){
|
||||
case WhiteSpace.NORMAL:
|
||||
nativeView.lineBreakMode = NSLineBreakMode.ByWordWrapping;
|
||||
nativeView.numberOfLines = 0;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
case WhiteSpace.NO_WRAP:
|
||||
nativeView.lineBreakMode = NSLineBreakMode.ByTruncatingTail;
|
||||
nativeView.numberOfLines = 1;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid whitespace value: ${value}. Valid values are: "${WhiteSpace.NORMAL}", "${WhiteSpace.NO_WRAP}".`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Label as LabelDefinition } from "ui/label";
|
||||
import { TextBase } from "ui/text-base";
|
||||
import { TextBase, WhiteSpace } from "ui/text-base";
|
||||
|
||||
export * from "ui/text-base";
|
||||
|
||||
@@ -7,10 +7,10 @@ export class Label extends TextBase implements LabelDefinition {
|
||||
private _android: android.widget.TextView;
|
||||
|
||||
get textWrap(): boolean {
|
||||
return this.style.whiteSpace === "normal";
|
||||
return this.style.whiteSpace === WhiteSpace.NORMAL;
|
||||
}
|
||||
set textWrap(value: boolean) {
|
||||
this.style.whiteSpace = value ? "normal" : "nowrap";
|
||||
this.style.whiteSpace = value ? WhiteSpace.NORMAL : WhiteSpace.NO_WRAP;
|
||||
}
|
||||
|
||||
get android(): android.widget.TextView {
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
Background, TextBase, View, layout, backgroundInternalProperty,
|
||||
borderTopWidthProperty, borderRightWidthProperty, borderBottomWidthProperty, borderLeftWidthProperty,
|
||||
paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty, whiteSpaceProperty,
|
||||
Length
|
||||
Length, WhiteSpace
|
||||
} from "ui/text-base";
|
||||
|
||||
import { ios } from "ui/styling/background";
|
||||
@@ -42,10 +42,10 @@ export class Label extends TextBase implements LabelDefinition {
|
||||
}
|
||||
|
||||
get textWrap(): boolean {
|
||||
return this.style.whiteSpace === "normal";
|
||||
return this.style.whiteSpace === WhiteSpace.NORMAL;
|
||||
}
|
||||
set textWrap(value: boolean) {
|
||||
this.style.whiteSpace = value ? "normal" : "nowrap";
|
||||
this.style.whiteSpace = value ? WhiteSpace.NORMAL : WhiteSpace.NO_WRAP;
|
||||
}
|
||||
|
||||
public onLoaded() {
|
||||
@@ -86,7 +86,7 @@ export class Label extends TextBase implements LabelDefinition {
|
||||
let nativeSize = nativeView.sizeThatFits(CGSizeMake(width, height));
|
||||
let labelWidth = nativeSize.width;
|
||||
|
||||
if (!this.textWrap && this.style.whiteSpace !== "nowrap") {
|
||||
if (this.textWrap) {
|
||||
labelWidth = Math.min(labelWidth, width);
|
||||
}
|
||||
|
||||
@@ -101,18 +101,22 @@ export class Label extends TextBase implements LabelDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
get [whiteSpaceProperty.native](): "nowrap" | "normal" {
|
||||
return "normal";
|
||||
get [whiteSpaceProperty.native](): WhiteSpace {
|
||||
return WhiteSpace.NORMAL;
|
||||
}
|
||||
set [whiteSpaceProperty.native](value: string) {
|
||||
set [whiteSpaceProperty.native](value: WhiteSpace) {
|
||||
let nativeView = this.nativeView;
|
||||
if (value === "normal") {
|
||||
switch(value){
|
||||
case WhiteSpace.NORMAL:
|
||||
nativeView.lineBreakMode = NSLineBreakMode.ByWordWrapping;
|
||||
nativeView.numberOfLines = 0;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
case WhiteSpace.NO_WRAP:
|
||||
nativeView.lineBreakMode = NSLineBreakMode.ByTruncatingTail;
|
||||
nativeView.numberOfLines = 1;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid whitespace value: ${value}. Valid values are: "${WhiteSpace.NORMAL}", "${WhiteSpace.NO_WRAP}".`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,54 +15,6 @@ export function fontSizeConverter(value: string): number {
|
||||
return floatConverter(value);
|
||||
}
|
||||
|
||||
export function textAlignConverter(value: string): string {
|
||||
switch (value) {
|
||||
case "left":
|
||||
case "center":
|
||||
case "right":
|
||||
return value;
|
||||
default:
|
||||
throw new Error("CSS text-align \"" + value + "\" is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
export function textDecorationConverter(value: string): string {
|
||||
const values = (value + "").split(" ");
|
||||
|
||||
if (values.indexOf("none") !== -1
|
||||
|| values.indexOf("underline") !== -1
|
||||
|| values.indexOf("line-through") !== -1
|
||||
|| values.indexOf("underline line-through") !== -1
|
||||
|| values.indexOf("line-through underline") !== -1
|
||||
) {
|
||||
return value;
|
||||
} else {
|
||||
throw new Error("CSS text-decoration \"" + value + "\" is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
export function whiteSpaceConverter(value: string): string {
|
||||
switch (value) {
|
||||
case "normal":
|
||||
case "nowrap":
|
||||
return value;
|
||||
default:
|
||||
throw new Error("CSS white-space \"" + value + "\" is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
export function textTransformConverter(value: string): string {
|
||||
switch (value) {
|
||||
case "none":
|
||||
case "uppercase":
|
||||
case "lowercase":
|
||||
case "capitalize":
|
||||
return value;
|
||||
default:
|
||||
throw new Error("CSS text-transform \"" + value + "\" is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
export const numberConverter = parseFloat;
|
||||
|
||||
export function visibilityConverter(value: string): string {
|
||||
|
||||
8
tns-core-modules/ui/styling/style.d.ts
vendored
8
tns-core-modules/ui/styling/style.d.ts
vendored
@@ -1,6 +1,6 @@
|
||||
declare module "ui/styling/style" {
|
||||
import { Length, PercentLength, Color, Background, Font, ViewBase, Observable } from "ui/core/view";
|
||||
import { TextDecoration } from "ui/text-base";
|
||||
import { TextAlignment, TextDecoration, TextTransform, WhiteSpace } from "ui/text-base";
|
||||
|
||||
export interface Thickness {
|
||||
left: number;
|
||||
@@ -86,10 +86,10 @@ declare module "ui/styling/style" {
|
||||
public visibility: "visible" | "hidden" | "collapse" | "collapsed";
|
||||
|
||||
public letterSpacing: number;
|
||||
public textAlignment: "left" | "center" | "right";
|
||||
public textAlignment: TextAlignment;
|
||||
public textDecoration: TextDecoration;
|
||||
public textTransform: "none" | "capitalize" | "uppercase" | "lowercase";
|
||||
public whiteSpace: "normal" | "nowrap";
|
||||
public textTransform: TextTransform;
|
||||
public whiteSpace: WhiteSpace;
|
||||
|
||||
public minWidth: Length;
|
||||
public minHeight: Length;
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
Order, FlexGrow, FlexShrink, FlexWrapBefore, AlignSelf
|
||||
} from "ui/layouts/flexbox-layout";
|
||||
|
||||
import { TextDecoration } from "ui/text-base";
|
||||
import { TextAlignment, TextDecoration, TextTransform, WhiteSpace } from "ui/text-base";
|
||||
|
||||
export class Style extends Observable implements StyleDefinition {
|
||||
constructor(public view: ViewBase) {
|
||||
@@ -65,10 +65,10 @@ export class Style extends Observable implements StyleDefinition {
|
||||
public visibility: "visible" | "hidden" | "collapse" | "collapsed";
|
||||
|
||||
public letterSpacing: number;
|
||||
public textAlignment: "left" | "center" | "right";
|
||||
public textAlignment: TextAlignment;
|
||||
public textDecoration: TextDecoration;
|
||||
public textTransform: "none" | "capitalize" | "uppercase" | "lowercase";
|
||||
public whiteSpace: "normal" | "nowrap";
|
||||
public textTransform: TextTransform;
|
||||
public whiteSpace: WhiteSpace;
|
||||
|
||||
public minWidth: Length;
|
||||
public minHeight: Length;
|
||||
|
||||
@@ -7,30 +7,6 @@ import { addWeakEventListener, removeWeakEventListener } from "ui/core/weak-even
|
||||
export { FormattedString };
|
||||
export * from "ui/core/view";
|
||||
|
||||
function onFormattedTextPropertyChanged(textBase: TextBaseCommon, oldValue: FormattedString, newValue: FormattedString) {
|
||||
if (oldValue) {
|
||||
oldValue.parent = null;
|
||||
removeWeakEventListener(oldValue, Observable.propertyChangeEvent, textBase.onFormattedTextChanged, textBase);
|
||||
}
|
||||
|
||||
if (newValue) {
|
||||
newValue.parent = textBase;
|
||||
addWeakEventListener(newValue, Observable.propertyChangeEvent, textBase.onFormattedTextChanged, textBase);
|
||||
}
|
||||
|
||||
// textBase._onFormattedTextPropertyChanged(newValue);
|
||||
}
|
||||
function onTextPropertyChanged(textBase: TextBaseCommon, oldValue: string, newValue: string) {
|
||||
// textBase._onTextPropertyChanged(newValue);
|
||||
|
||||
// //RemoveThisDoubleCall
|
||||
// textBase.style._updateTextTransform();
|
||||
// textBase.style._updateTextDecoration();
|
||||
}
|
||||
|
||||
// (<proxy.PropertyMetadata>textProperty.metadata).onSetNativeValue = onTextPropertyChanged;
|
||||
// (<proxy.PropertyMetadata>formattedTextProperty.metadata).onSetNativeValue = onFormattedTextPropertyChanged;
|
||||
|
||||
export abstract class TextBaseCommon extends View implements TextBaseDefinition, FormattedStringView {
|
||||
|
||||
constructor() {
|
||||
@@ -39,24 +15,11 @@ export abstract class TextBaseCommon extends View implements TextBaseDefinition,
|
||||
this.formattedText = new FormattedString();
|
||||
}
|
||||
|
||||
public abstract _setFormattedTextPropertyToNative(value): void;
|
||||
|
||||
// public _onBindingContextChanged(oldValue: any, newValue: any) {
|
||||
// super._onBindingContextChanged(oldValue, newValue);
|
||||
// if (this.formattedText) {
|
||||
// this.formattedText.updateSpansBindingContext(newValue);
|
||||
// }
|
||||
|
||||
// //This is because of ListView virtualization
|
||||
// //RemoveThisDoubleCall
|
||||
// this.style._updateTextTransform();
|
||||
// this.style._updateTextDecoration();
|
||||
// }
|
||||
public abstract _setFormattedTextPropertyToNative(value: FormattedString): void;
|
||||
|
||||
public text: string;
|
||||
public formattedText: FormattedString;
|
||||
|
||||
// TODO: Do we need to export these properties here??
|
||||
get fontSize(): number {
|
||||
return this.style.fontSize;
|
||||
}
|
||||
@@ -71,10 +34,10 @@ export abstract class TextBaseCommon extends View implements TextBaseDefinition,
|
||||
this.style.letterSpacing = value;
|
||||
}
|
||||
|
||||
get textAlignment(): "left" | "center" | "right" {
|
||||
get textAlignment(): TextAlignment {
|
||||
return this.style.textAlignment;
|
||||
}
|
||||
set textAlignment(value: "left" | "center" | "right") {
|
||||
set textAlignment(value: TextAlignment) {
|
||||
this.style.textAlignment = value;
|
||||
}
|
||||
|
||||
@@ -85,17 +48,17 @@ export abstract class TextBaseCommon extends View implements TextBaseDefinition,
|
||||
this.style.textDecoration = value;
|
||||
}
|
||||
|
||||
get textTransform(): "none" | "capitalize" | "uppercase" | "lowercase" {
|
||||
get textTransform(): TextTransform {
|
||||
return this.style.textTransform;
|
||||
}
|
||||
set textTransform(value: "none" | "capitalize" | "uppercase" | "lowercase") {
|
||||
set textTransform(value: TextTransform) {
|
||||
this.style.textTransform = value;
|
||||
}
|
||||
|
||||
get whiteSpace(): "normal" | "nowrap" {
|
||||
get whiteSpace(): WhiteSpace {
|
||||
return this.style.whiteSpace;
|
||||
}
|
||||
set whiteSpace(value: "normal" | "nowrap") {
|
||||
set whiteSpace(value: WhiteSpace) {
|
||||
this.style.whiteSpace = value;
|
||||
}
|
||||
|
||||
@@ -114,28 +77,40 @@ export abstract class TextBaseCommon extends View implements TextBaseDefinition,
|
||||
}
|
||||
}
|
||||
|
||||
//Text
|
||||
export const textProperty = new Property<TextBaseCommon, string>({ name: "text", defaultValue: "" });
|
||||
textProperty.register(TextBaseCommon);
|
||||
|
||||
//FormattedText
|
||||
export const formattedTextProperty = new Property<TextBaseCommon, FormattedString>({ name: "formattedText", affectsLayout: isIOS, valueChanged: onFormattedTextPropertyChanged });
|
||||
formattedTextProperty.register(TextBaseCommon);
|
||||
|
||||
export const textAlignmentProperty = new InheritedCssProperty<Style, "left" | "center" | "right">({
|
||||
name: "textAlignment", cssName: "text-align", valueConverter: (value) => {
|
||||
switch (value) {
|
||||
case "left":
|
||||
case "center":
|
||||
case "right":
|
||||
return <"left" | "center" | "right">value;
|
||||
function onFormattedTextPropertyChanged(textBase: TextBaseCommon, oldValue: FormattedString, newValue: FormattedString) {
|
||||
if (oldValue) {
|
||||
oldValue.parent = null;
|
||||
removeWeakEventListener(oldValue, Observable.propertyChangeEvent, textBase.onFormattedTextChanged, textBase);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`CSS text-align ${value} is not supported.`);
|
||||
if (newValue) {
|
||||
newValue.parent = textBase;
|
||||
addWeakEventListener(newValue, Observable.propertyChangeEvent, textBase.onFormattedTextChanged, textBase);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//TextAlignment
|
||||
export type TextAlignment = "left" | "center" | "right";
|
||||
export namespace TextAlignment {
|
||||
export const LEFT: "left" = "left";
|
||||
export const CENTER: "center" = "center";
|
||||
export const RIGHT: "right" = "right";
|
||||
export const isValid = makeValidator<TextAlignment>(LEFT, CENTER, RIGHT);
|
||||
export const parse = makeParser(isValid, undefined);
|
||||
}
|
||||
|
||||
export const textAlignmentProperty = new InheritedCssProperty<Style, TextAlignment>({name: "textAlignment", cssName: "text-align", valueConverter: TextAlignment.parse});
|
||||
textAlignmentProperty.register(Style);
|
||||
|
||||
// TextDecoration
|
||||
//TextDecoration
|
||||
export type TextDecoration = "none" | "underline" | "line-through" | "underline line-through";
|
||||
export namespace TextDecoration {
|
||||
export const NONE: "none" = "none";
|
||||
@@ -146,37 +121,32 @@ export namespace TextDecoration {
|
||||
export const isValid = makeValidator<TextDecoration>(NONE, UNDERLINE, LINE_THROUGH, UNDERLINE_LINE_THROUGH);
|
||||
export const parse = makeParser(isValid, NONE);
|
||||
}
|
||||
export const textDecorationProperty = new CssProperty<Style, TextDecoration>({
|
||||
name: "textDecoration", cssName: "text-decoration", defaultValue: TextDecoration.NONE, valueConverter: TextDecoration.parse});
|
||||
export const textDecorationProperty = new CssProperty<Style, TextDecoration>({name: "textDecoration", cssName: "text-decoration", defaultValue: TextDecoration.NONE, valueConverter: TextDecoration.parse});
|
||||
textDecorationProperty.register(Style);
|
||||
|
||||
export const textTransformProperty = new CssProperty<Style, "none" | "capitalize" | "uppercase" | "lowercase">({
|
||||
name: "textTransform", cssName: "text-transform", defaultValue: "none", valueConverter: (value) => {
|
||||
switch (value) {
|
||||
case "none":
|
||||
case "uppercase":
|
||||
case "lowercase":
|
||||
case "capitalize":
|
||||
return <"none" | "capitalize" | "uppercase" | "lowercase">value;
|
||||
|
||||
default:
|
||||
throw new Error(`CSS text-transform ${value} is not supported.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
//TextTransform
|
||||
export type TextTransform = "none" | "capitalize" | "uppercase" | "lowercase";
|
||||
export namespace TextTransform {
|
||||
export const NONE: "none" = "none";
|
||||
export const CAPITALIZE: "capitalize" = "capitalize";
|
||||
export const UPPERCASE: "uppercase" = "uppercase";
|
||||
export const LOWERCASE: "lowercase" ="lowercase";
|
||||
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});
|
||||
textTransformProperty.register(Style);
|
||||
|
||||
export const whiteSpaceProperty = new CssProperty<Style, "normal" | "nowrap">({
|
||||
name: "whiteSpace", cssName: "white-space", valueConverter: (value: "normal" | "nowrap") => {
|
||||
switch (value) {
|
||||
case "normal":
|
||||
case "nowrap":
|
||||
return value;
|
||||
default:
|
||||
throw new Error(`CSS white-space ${value} is not supported.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
//Whitespace
|
||||
export type WhiteSpace = "normal" | "nowrap";
|
||||
export namespace WhiteSpace {
|
||||
export const NORMAL: "normal" = "normal";
|
||||
export const NO_WRAP: "nowrap" = "nowrap";
|
||||
export const isValid = makeValidator<WhiteSpace>(NORMAL, NO_WRAP);
|
||||
export const parse = makeParser(isValid, NORMAL);
|
||||
}
|
||||
|
||||
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) });
|
||||
|
||||
@@ -1,83 +1,15 @@
|
||||
import {
|
||||
TextBaseCommon, textProperty, formattedTextProperty, textAlignmentProperty, textDecorationProperty,
|
||||
textTransformProperty, letterSpacingProperty, colorProperty, fontInternalProperty, whiteSpaceProperty,
|
||||
Font, Color, FormattedString, TextDecoration
|
||||
Font, Color, FormattedString, TextDecoration, TextAlignment, TextTransform, WhiteSpace
|
||||
} from "./text-base-common";
|
||||
|
||||
export * from "./text-base-common";
|
||||
|
||||
function getCapitalizedString(str: string): string {
|
||||
let words = str.split(" ");
|
||||
let newWords = [];
|
||||
for (let i = 0, length = words.length; i < length; i++) {
|
||||
let word = words[i].toLowerCase();
|
||||
newWords.push(word.substr(0, 1).toUpperCase() + word.substring(1));
|
||||
}
|
||||
|
||||
return newWords.join(" ");
|
||||
}
|
||||
|
||||
export function getTransformedText(text: string, transform: "none" | "capitalize" | "uppercase" | "lowercase"): string {
|
||||
switch (transform) {
|
||||
case "uppercase":
|
||||
return text.toUpperCase();
|
||||
|
||||
case "lowercase":
|
||||
return text.toLowerCase();
|
||||
|
||||
case "capitalize":
|
||||
return getCapitalizedString(text);
|
||||
|
||||
default:
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
@Interfaces([android.text.method.TransformationMethod])
|
||||
class TextTransformation extends android.text.method.ReplacementTransformationMethod {
|
||||
constructor(public originalText: string, public formattedText: FormattedString, public textTransform: "none" | "capitalize" | "uppercase" | "lowercase") {
|
||||
super();
|
||||
return global.__native(this);
|
||||
}
|
||||
|
||||
protected getOriginal(): native.Array<string> {
|
||||
return this.formattedText ? this.formattedText._formattedText : this.originalText;
|
||||
}
|
||||
|
||||
protected getReplacement(): native.Array<string> {
|
||||
let result: 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);
|
||||
}
|
||||
} else {
|
||||
result = getTransformedText(this.originalText, textTransform);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export class TextBase extends TextBaseCommon {
|
||||
_transformationMethod: any;
|
||||
_nativeView: android.widget.TextView;
|
||||
|
||||
public _setFormattedTextPropertyToNative(value: FormattedString) {
|
||||
// TODO: Check if there is an option to force call the transformation method without
|
||||
// creating new native instance.
|
||||
if (this._nativeView) {
|
||||
this._nativeView.setTransformationMethod(new TextTransformation(this.text, value, this.style.textTransform));
|
||||
}
|
||||
|
||||
let newText = value ? value._formattedText : null;
|
||||
if (this._nativeView) {
|
||||
this._nativeView.setText(newText);
|
||||
}
|
||||
}
|
||||
|
||||
//Text
|
||||
get [textProperty.native](): string {
|
||||
return this._nativeView.getText();
|
||||
}
|
||||
@@ -89,6 +21,7 @@ export class TextBase extends TextBaseCommon {
|
||||
this._nativeView.setText(value);
|
||||
}
|
||||
|
||||
//FormattedText
|
||||
get [formattedTextProperty.native](): FormattedString {
|
||||
return null;
|
||||
}
|
||||
@@ -96,6 +29,7 @@ export class TextBase extends TextBaseCommon {
|
||||
this._setFormattedTextPropertyToNative(value);
|
||||
}
|
||||
|
||||
//Color
|
||||
get [colorProperty.native](): android.content.res.ColorStateList {
|
||||
return this._nativeView.getTextColors();
|
||||
}
|
||||
@@ -107,6 +41,7 @@ export class TextBase extends TextBaseCommon {
|
||||
}
|
||||
}
|
||||
|
||||
//FontInternal
|
||||
get [fontInternalProperty.native](): { typeface: android.graphics.Typeface, fontSize: number } {
|
||||
let textView = this._nativeView;
|
||||
return {
|
||||
@@ -130,74 +65,118 @@ export class TextBase extends TextBaseCommon {
|
||||
textView.setTypeface(typeface);
|
||||
}
|
||||
|
||||
get [textAlignmentProperty.native](): string {
|
||||
let textGravity = this._nativeView.getGravity() & android.view.View.TEXT_ALIGNMENT_GRAVITY;
|
||||
switch (textGravity) {
|
||||
//TextAlignment
|
||||
get [textAlignmentProperty.native](): TextAlignment {
|
||||
let textAlignmentGravity = this._nativeView.getGravity() & android.view.View.TEXT_ALIGNMENT_GRAVITY;
|
||||
switch (textAlignmentGravity) {
|
||||
case android.view.Gravity.LEFT:
|
||||
return "left";
|
||||
|
||||
return TextAlignment.LEFT;
|
||||
case android.view.Gravity.CENTER_HORIZONTAL:
|
||||
return "center";
|
||||
|
||||
return TextAlignment.CENTER;
|
||||
case android.view.Gravity.RIGHT:
|
||||
return "right";
|
||||
|
||||
return TextAlignment.RIGHT;
|
||||
default:
|
||||
throw new Error("Invalid textGravity: " + textGravity);
|
||||
throw new Error(`Unsupported android.view.View.TEXT_ALIGNMENT_GRAVITY: ${textAlignmentGravity}. Currently supported values are android.view.Gravity.LEFT, android.view.Gravity.CENTER_HORIZONTAL, and android.view.Gravity.RIGHT.`);
|
||||
}
|
||||
}
|
||||
set [textAlignmentProperty.native](value: string) {
|
||||
set [textAlignmentProperty.native](value: TextAlignment) {
|
||||
let verticalGravity = this._nativeView.getGravity() & android.view.Gravity.VERTICAL_GRAVITY_MASK;
|
||||
switch (value) {
|
||||
case "left":
|
||||
case TextAlignment.LEFT:
|
||||
this._nativeView.setGravity(android.view.Gravity.LEFT | verticalGravity);
|
||||
break;
|
||||
case "center":
|
||||
case TextAlignment.CENTER:
|
||||
this._nativeView.setGravity(android.view.Gravity.CENTER_HORIZONTAL | verticalGravity);
|
||||
break;
|
||||
case "right":
|
||||
case TextAlignment.RIGHT:
|
||||
this._nativeView.setGravity(android.view.Gravity.RIGHT | verticalGravity);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
throw new Error(`Invalid text alignment value: ${value}. Valid values are: "${TextAlignment.LEFT}", "${TextAlignment.CENTER}", "${TextAlignment.RIGHT}".`);
|
||||
}
|
||||
}
|
||||
|
||||
//TextDecoration
|
||||
get [textDecorationProperty.native](): TextDecoration {
|
||||
return "none";
|
||||
return TextDecoration.NONE;
|
||||
}
|
||||
set [textDecorationProperty.native](value: TextDecoration) {
|
||||
let flags = 0;
|
||||
let values = (value + "").split(" ");
|
||||
let flags: number;
|
||||
|
||||
if (values.indexOf("underline") !== -1) {
|
||||
flags = flags | android.graphics.Paint.UNDERLINE_TEXT_FLAG;
|
||||
switch(value){
|
||||
case TextDecoration.NONE:
|
||||
flags = 0;
|
||||
break;
|
||||
case TextDecoration.UNDERLINE:
|
||||
flags = android.graphics.Paint.UNDERLINE_TEXT_FLAG;
|
||||
break;
|
||||
case TextDecoration.LINE_THROUGH:
|
||||
flags = android.graphics.Paint.STRIKE_THRU_TEXT_FLAG;
|
||||
break;
|
||||
case TextDecoration.UNDERLINE_LINE_THROUGH:
|
||||
flags = android.graphics.Paint.UNDERLINE_TEXT_FLAG | android.graphics.Paint.STRIKE_THRU_TEXT_FLAG;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid text decoration value: ${value}. Valid values are: "${TextDecoration.NONE}", "${TextDecoration.UNDERLINE}", "${TextDecoration.LINE_THROUGH}", "${TextDecoration.UNDERLINE_LINE_THROUGH}".`);
|
||||
}
|
||||
|
||||
if (values.indexOf("line-through") !== -1) {
|
||||
flags = flags | android.graphics.Paint.STRIKE_THRU_TEXT_FLAG;
|
||||
}
|
||||
|
||||
if (values.indexOf("none") === -1) {
|
||||
this._nativeView.setPaintFlags(flags);
|
||||
} else {
|
||||
this._nativeView.setPaintFlags(0);
|
||||
}
|
||||
}
|
||||
|
||||
get [textTransformProperty.native](): "none" | "capitalize" | "uppercase" | "lowercase" {
|
||||
return "none";
|
||||
//TextTransform
|
||||
get [textTransformProperty.native](): TextTransform {
|
||||
return TextTransform.NONE;
|
||||
}
|
||||
set [textTransformProperty.native](value: "none" | "capitalize" | "uppercase" | "lowercase") {
|
||||
set [textTransformProperty.native](value: TextTransform) {
|
||||
this._setFormattedTextPropertyToNative(this.formattedText);
|
||||
}
|
||||
|
||||
get [whiteSpaceProperty.native](): "normal" | "nowrap" {
|
||||
return "normal";
|
||||
private _originalTransformationMethod: android.text.method.TransformationMethod;
|
||||
public _setFormattedTextPropertyToNative(value: FormattedString) {
|
||||
// TODO: Check if there is an option to force call the transformation method without
|
||||
// creating new native instance.
|
||||
if (!this._nativeView) {
|
||||
return;
|
||||
}
|
||||
set [whiteSpaceProperty.native](value: "normal" | "nowrap") {
|
||||
|
||||
if (!this._originalTransformationMethod) {
|
||||
this._originalTransformationMethod = this.android.getTransformationMethod();
|
||||
}
|
||||
|
||||
let newText = value ? value._formattedText : null;//newText is of type android.text.SpannableStringBuilder
|
||||
if (newText) {
|
||||
this._nativeView.setTransformationMethod(new TextTransformation(this.text, value, this.style.textTransform));
|
||||
}
|
||||
else {
|
||||
if (this._originalTransformationMethod) {
|
||||
this.android.setTransformationMethod(this._originalTransformationMethod);
|
||||
this._originalTransformationMethod = null;
|
||||
}
|
||||
}
|
||||
|
||||
this._nativeView.setText(newText);
|
||||
}
|
||||
|
||||
//WhiteSpace
|
||||
get [whiteSpaceProperty.native](): WhiteSpace {
|
||||
return WhiteSpace.NORMAL;
|
||||
}
|
||||
set [whiteSpaceProperty.native](value: WhiteSpace) {
|
||||
let nativeView = this._nativeView;
|
||||
let nowrap = value === "nowrap";
|
||||
switch(value){
|
||||
case WhiteSpace.NORMAL:
|
||||
nativeView.setSingleLine(false);
|
||||
nativeView.setEllipsize(null);
|
||||
break;
|
||||
case WhiteSpace.NO_WRAP:
|
||||
nativeView.setSingleLine(true);
|
||||
nativeView.setEllipsize(android.text.TextUtils.TruncateAt.END);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid whitespace value: ${value}. Valid values are: "${WhiteSpace.NORMAL}", "${WhiteSpace.NO_WRAP}".`);
|
||||
}
|
||||
|
||||
let nowrap = value === WhiteSpace.NO_WRAP;
|
||||
nativeView.setSingleLine(nowrap);
|
||||
nativeView.setEllipsize(nowrap ? android.text.TextUtils.TruncateAt.END : null);
|
||||
}
|
||||
@@ -209,3 +188,58 @@ export class TextBase extends TextBaseCommon {
|
||||
org.nativescript.widgets.ViewHelper.setLetterspacing(this._nativeView, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Interfaces([android.text.method.TransformationMethod])
|
||||
class TextTransformation extends android.text.method.ReplacementTransformationMethod {
|
||||
constructor(public originalText: string, public formattedText: FormattedString, public textTransform: TextTransform) {
|
||||
super();
|
||||
return global.__native(this);
|
||||
}
|
||||
|
||||
protected getOriginal(): native.Array<string> {
|
||||
return this.formattedText ? this.formattedText._formattedText : this.originalText;
|
||||
}
|
||||
|
||||
protected getReplacement(): native.Array<string> {
|
||||
let result: 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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = getTransformedText(this.originalText, textTransform);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function getCapitalizedString(str: string): string {
|
||||
let words = str.split(" ");
|
||||
let newWords = [];
|
||||
for (let i = 0, length = words.length; i < length; i++) {
|
||||
let word = words[i].toLowerCase();
|
||||
newWords.push(word.substr(0, 1).toUpperCase() + word.substring(1));
|
||||
}
|
||||
|
||||
return newWords.join(" ");
|
||||
}
|
||||
|
||||
export function getTransformedText(text: string, textTransform: TextTransform): string {
|
||||
switch (textTransform) {
|
||||
case TextTransform.NONE:
|
||||
return text;
|
||||
case TextTransform.UPPERCASE:
|
||||
return text.toUpperCase();
|
||||
case TextTransform.LOWERCASE:
|
||||
return text.toLowerCase();
|
||||
case TextTransform.CAPITALIZE:
|
||||
return getCapitalizedString(text);
|
||||
default:
|
||||
throw new Error(`Invalid text transform value: ${textTransform}. Valid values are: "${TextTransform.NONE}", "${TextTransform.CAPITALIZE}", "${TextTransform.UPPERCASE}, "${TextTransform.LOWERCASE}".`);
|
||||
}
|
||||
}
|
||||
47
tns-core-modules/ui/text-base/text-base.d.ts
vendored
47
tns-core-modules/ui/text-base/text-base.d.ts
vendored
@@ -32,7 +32,7 @@
|
||||
/**
|
||||
* Gets or sets text-alignment style property.
|
||||
*/
|
||||
textAlignment: "left" | "center" | "right";
|
||||
textAlignment: TextAlignment;
|
||||
|
||||
/**
|
||||
* Gets or sets text decorations style property.
|
||||
@@ -42,12 +42,12 @@
|
||||
/**
|
||||
* Gets or sets text transform style property.
|
||||
*/
|
||||
textTransform: "none" | "capitalize" | "uppercase" | "lowercase";
|
||||
textTransform: TextTransform;
|
||||
|
||||
/**
|
||||
* Gets or sets white space style property.
|
||||
*/
|
||||
whiteSpace: "normal" | "nowrap";
|
||||
whiteSpace: WhiteSpace;
|
||||
|
||||
/**
|
||||
* Called for every child element declared in xml.
|
||||
@@ -57,9 +57,6 @@
|
||||
*/
|
||||
_addChildFromBuilder(name: string, value: any): void;
|
||||
|
||||
//@private
|
||||
// _onTextPropertyChanged(value: string): void;
|
||||
// _setFormattedTextPropertyToNative(value: any): void;
|
||||
/**
|
||||
* @private
|
||||
* Called when the text property is changed to request layout.
|
||||
@@ -68,6 +65,18 @@
|
||||
//@endprivate
|
||||
}
|
||||
|
||||
export const textProperty: Property<TextBase, string>;
|
||||
export const formattedTextProperty: Property<TextBase, FormattedString>;
|
||||
|
||||
export type TextAlignment = "left" | "center" | "right";
|
||||
export namespace TextAlignment {
|
||||
export const LEFT: "left";
|
||||
export const CENTER: "center";
|
||||
export const RIGHT: "right";
|
||||
export function isValid(value: any): boolean;
|
||||
export function parse(value: string): TextAlignment;
|
||||
}
|
||||
|
||||
export type TextDecoration = "none" | "underline" | "line-through" | "underline line-through";
|
||||
export namespace TextDecoration {
|
||||
export const NONE: "none";
|
||||
@@ -79,15 +88,29 @@
|
||||
}
|
||||
|
||||
export type TextTransform = "none" | "capitalize" | "uppercase" | "lowercase";
|
||||
export namespace TextTransform {
|
||||
export const NONE: "none";
|
||||
export const CAPITALIZE: "capitalize";
|
||||
export const UPPERCASE: "uppercase";
|
||||
export const LOWERCASE: "lowercase";
|
||||
export function isValid(value: any): boolean;
|
||||
export function parse(value: string): TextTransform;
|
||||
}
|
||||
|
||||
export function getTransformedText(text: string, transform: TextTransform): string;
|
||||
export type WhiteSpace = "normal" | "nowrap";
|
||||
export namespace WhiteSpace {
|
||||
export const NORMAL: "normal";
|
||||
export const NO_WRAP: "nowrap";
|
||||
export function isValid(value: any): boolean;
|
||||
export function parse(value: string): WhiteSpace;
|
||||
}
|
||||
|
||||
export const textProperty: Property<TextBase, string>;
|
||||
export const formattedTextProperty: Property<TextBase, FormattedString>;
|
||||
|
||||
export const textAlignmentProperty: InheritedCssProperty<Style, "left" | "center" | "right">;
|
||||
export const textAlignmentProperty: InheritedCssProperty<Style, TextAlignment>;
|
||||
export const textDecorationProperty: CssProperty<Style, TextDecoration>;
|
||||
export const textTransformProperty: CssProperty<Style, TextTransform>;
|
||||
export const whiteSpaceProperty: CssProperty<Style, "normal" | "nowrap">;
|
||||
export const whiteSpaceProperty: CssProperty<Style, WhiteSpace>;
|
||||
export const letterSpacingProperty: CssProperty<Style, number>;
|
||||
|
||||
//Used by tab view
|
||||
export function getTransformedText(text: string, textTransform: TextTransform): string;
|
||||
}
|
||||
@@ -1,155 +1,15 @@
|
||||
import {
|
||||
TextBaseCommon, textProperty, formattedTextProperty, textAlignmentProperty, textDecorationProperty,
|
||||
textTransformProperty, letterSpacingProperty, colorProperty, fontInternalProperty, Font, Color, FormattedString,
|
||||
TextDecoration
|
||||
TextDecoration, TextAlignment, TextTransform
|
||||
} from "./text-base-common";
|
||||
|
||||
export * from "./text-base-common";
|
||||
|
||||
function NSStringFromNSAttributedString(source: NSAttributedString | string): NSString {
|
||||
return NSString.stringWithString(source instanceof NSAttributedString && source.string || <string>source);
|
||||
}
|
||||
|
||||
export function getTransformedText(text: string, transform: "none" | "capitalize" | "uppercase" | "lowercase"): string {
|
||||
switch (transform) {
|
||||
case "uppercase":
|
||||
return NSStringFromNSAttributedString(text).uppercaseString;
|
||||
|
||||
case "lowercase":
|
||||
return NSStringFromNSAttributedString(text).lowercaseString;
|
||||
|
||||
case "capitalize":
|
||||
return NSStringFromNSAttributedString(text).capitalizedString;
|
||||
|
||||
case "none":
|
||||
default:
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
function updateFormattedStringTextDecoration(formattedText: FormattedString, decoration: string, ): void {
|
||||
|
||||
// TODO: Refactor this method so it doesn't modify FormattedString properties.
|
||||
// Instead it should create NSAttributedString and apply it to the nativeView.
|
||||
let textDecoration = decoration + "";
|
||||
if (textDecoration.indexOf("none") !== -1) {
|
||||
formattedText.underline = NSUnderlineStyle.StyleNone;
|
||||
formattedText.strikethrough = NSUnderlineStyle.StyleNone;
|
||||
}
|
||||
else {
|
||||
if (textDecoration.indexOf("underline") !== -1) {
|
||||
formattedText.underline = NSUnderlineStyle.StyleSingle;
|
||||
} else {
|
||||
formattedText.underline = NSUnderlineStyle.StyleNone;
|
||||
}
|
||||
|
||||
if (textDecoration.indexOf("line-through") !== -1) {
|
||||
formattedText.strikethrough = NSUnderlineStyle.StyleSingle;
|
||||
} else {
|
||||
formattedText.strikethrough = NSUnderlineStyle.StyleNone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateFormattedStringTextTransformation(formattedText: FormattedString, transform: "none" | "capitalize" | "uppercase" | "lowercase"): void {
|
||||
// TODO: Refactor this method so it doesn't modify Span properties.
|
||||
// Instead it should create NSAttributedString and apply it to the nativeView.
|
||||
for (let i = 0, length = formattedText.spans.length; i < length; i++) {
|
||||
let span = formattedText.spans.getItem(i);
|
||||
span.text = getTransformedText(span.text, transform);
|
||||
}
|
||||
}
|
||||
|
||||
function setFormattedTextDecorationAndTransform(formattedText: FormattedString, nativeView: UITextField | UITextView | UILabel | UIButton, decoration: string, transform: "none" | "capitalize" | "uppercase" | "lowercase", letterSpacing: number) {
|
||||
updateFormattedStringTextDecoration(formattedText, decoration);
|
||||
updateFormattedStringTextTransformation(formattedText, transform);
|
||||
|
||||
if (typeof letterSpacing === "number" && !isNaN(letterSpacing)) {
|
||||
if (nativeView instanceof UIButton) {
|
||||
let attrText = NSMutableAttributedString.alloc().initWithAttributedString(nativeView.attributedTitleForState(UIControlState.Normal));
|
||||
attrText.addAttributeValueRange(NSKernAttributeName, letterSpacing * nativeView.font.pointSize, { location: 0, length: attrText.length });
|
||||
nativeView.setAttributedTitleForState(attrText, UIControlState.Normal);
|
||||
} else {
|
||||
let attrText = NSMutableAttributedString.alloc().initWithAttributedString(nativeView.attributedText);
|
||||
attrText.addAttributeValueRange(NSKernAttributeName, letterSpacing * nativeView.font.pointSize, { location: 0, length: attrText.length });
|
||||
nativeView.attributedText = attrText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setTextDecorationAndTransform(text: string, nativeView: UITextField | UITextView | UILabel | UIButton, decoration: string, transform: "none" | "capitalize" | "uppercase" | "lowercase", letterSpacing: number, color: Color) {
|
||||
let hasLetterSpacing = typeof letterSpacing === "number" && !isNaN(letterSpacing);
|
||||
|
||||
let decorationValues = decoration + "";
|
||||
let dict = new Map<string, number>();
|
||||
if (decorationValues.indexOf("none") === -1) {
|
||||
if (decorationValues.indexOf("underline") !== -1) {
|
||||
dict.set(NSUnderlineStyleAttributeName, NSUnderlineStyle.StyleSingle);
|
||||
}
|
||||
|
||||
if (decorationValues.indexOf("line-through") !== -1) {
|
||||
dict.set(NSStrikethroughStyleAttributeName, NSUnderlineStyle.StyleSingle);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasLetterSpacing) {
|
||||
dict.set(NSKernAttributeName, letterSpacing * nativeView.font.pointSize);
|
||||
}
|
||||
|
||||
if (color) {
|
||||
dict.set(NSForegroundColorAttributeName, color.ios);
|
||||
}
|
||||
|
||||
let source = getTransformedText(text, transform);
|
||||
if (dict.size > 0) {
|
||||
let result = NSMutableAttributedString.alloc().initWithString(source);
|
||||
result.setAttributesRange(<any>dict, { location: 0, length: source.length });
|
||||
if (nativeView instanceof UIButton) {
|
||||
nativeView.setAttributedTitleForState(result, UIControlState.Normal);
|
||||
} else {
|
||||
nativeView.attributedText = result;
|
||||
}
|
||||
} else {
|
||||
if (nativeView instanceof UIButton) {
|
||||
// Clear attributedText or title won't be affected.
|
||||
nativeView.setAttributedTitleForState(null, UIControlState.Normal);
|
||||
nativeView.setTitleForState(source, UIControlState.Normal);
|
||||
} else {
|
||||
// Clear attributedText or text won't be affected.
|
||||
nativeView.attributedText = undefined;
|
||||
nativeView.text = source;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class TextBase extends TextBaseCommon {
|
||||
|
||||
public nativeView: UITextField | UITextView | UILabel | UIButton;
|
||||
|
||||
// public _onTextPropertyChanged(value: string) {
|
||||
// var newValue = toUIString(value);
|
||||
// this.ios.text = newValue;
|
||||
|
||||
// //RemoveThisDoubleCall
|
||||
// // this.style._updateTextDecoration();
|
||||
// // this.style._updateTextTransform();
|
||||
|
||||
// this._requestLayoutOnTextChanged();
|
||||
// }
|
||||
|
||||
public _setFormattedTextPropertyToNative(value: FormattedString) {
|
||||
let newText = value ? value._formattedText : null;
|
||||
let nativeView = this.nativeView;
|
||||
if (nativeView instanceof UIButton) {
|
||||
nativeView.setAttributedTitleForState(newText, UIControlState.Normal);
|
||||
} else {
|
||||
nativeView.attributedText = newText;
|
||||
}
|
||||
//RemoveThisDoubleCall
|
||||
// this.style._updateTextDecoration();
|
||||
// this.style._updateTextTransform();
|
||||
}
|
||||
|
||||
//Text
|
||||
get [textProperty.native](): string {
|
||||
let nativeView = this.nativeView;
|
||||
if (nativeView instanceof UIButton) {
|
||||
@@ -176,6 +36,7 @@ export class TextBase extends TextBaseCommon {
|
||||
this._requestLayoutOnTextChanged();
|
||||
}
|
||||
|
||||
//FormattedText
|
||||
get [formattedTextProperty.native](): FormattedString {
|
||||
return null;
|
||||
}
|
||||
@@ -183,6 +44,17 @@ export class TextBase extends TextBaseCommon {
|
||||
this._setFormattedTextPropertyToNative(value);
|
||||
}
|
||||
|
||||
public _setFormattedTextPropertyToNative(value: FormattedString) {
|
||||
let newText = value ? value._formattedText : null;
|
||||
let nativeView = this.nativeView;
|
||||
if (nativeView instanceof UIButton) {
|
||||
nativeView.setAttributedTitleForState(newText, UIControlState.Normal);
|
||||
} else {
|
||||
nativeView.attributedText = newText;
|
||||
}
|
||||
}
|
||||
|
||||
//Color
|
||||
get [colorProperty.native](): UIColor {
|
||||
let nativeView = this.nativeView;
|
||||
if (nativeView instanceof UIButton) {
|
||||
@@ -200,6 +72,7 @@ export class TextBase extends TextBaseCommon {
|
||||
}
|
||||
}
|
||||
|
||||
//FontInternal
|
||||
get [fontInternalProperty.native](): UIFont {
|
||||
let nativeView = this.nativeView;
|
||||
nativeView = nativeView instanceof UIButton ? nativeView.titleLabel : nativeView;
|
||||
@@ -212,41 +85,43 @@ export class TextBase extends TextBaseCommon {
|
||||
nativeView.font = font;
|
||||
}
|
||||
|
||||
get [textAlignmentProperty.native](): string {
|
||||
//TextAlignment
|
||||
get [textAlignmentProperty.native](): TextAlignment {
|
||||
let nativeView = this.nativeView;
|
||||
nativeView = nativeView instanceof UIButton ? nativeView.titleLabel : nativeView;
|
||||
switch (nativeView.textAlignment) {
|
||||
case NSTextAlignment.Left:
|
||||
return "left";
|
||||
|
||||
return TextAlignment.LEFT;
|
||||
case NSTextAlignment.Center:
|
||||
return "center";
|
||||
|
||||
return TextAlignment.CENTER;
|
||||
case NSTextAlignment.Right:
|
||||
return "right";
|
||||
return TextAlignment.RIGHT;
|
||||
default:
|
||||
throw new Error(`Unsupported NSTextAlignment: ${nativeView.textAlignment}. Currently supported values are NSTextAlignment.Left, NSTextAlignment.Center, and NSTextAlignment.Right.`);
|
||||
}
|
||||
}
|
||||
set [textAlignmentProperty.native](value: string) {
|
||||
set [textAlignmentProperty.native](value: TextAlignment) {
|
||||
let nativeView = this.nativeView;
|
||||
nativeView = nativeView instanceof UIButton ? nativeView.titleLabel : nativeView;
|
||||
// NOTE: if Button textAlignment is not enough - set also btn.contentHorizontalAlignment
|
||||
switch (value) {
|
||||
case "left":
|
||||
case TextAlignment.LEFT:
|
||||
nativeView.textAlignment = NSTextAlignment.Left;
|
||||
break;
|
||||
case "center":
|
||||
case TextAlignment.CENTER:
|
||||
nativeView.textAlignment = NSTextAlignment.Center;
|
||||
break;
|
||||
case "right":
|
||||
case TextAlignment.RIGHT:
|
||||
nativeView.textAlignment = NSTextAlignment.Right;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
throw new Error(`Invalid text alignment value: ${value}. Valid values are: "${TextAlignment.LEFT}", "${TextAlignment.CENTER}", "${TextAlignment.RIGHT}".`);
|
||||
}
|
||||
}
|
||||
|
||||
//TextDecoration
|
||||
get [textDecorationProperty.native](): TextDecoration {
|
||||
return "none";
|
||||
return TextDecoration.NONE;
|
||||
}
|
||||
set [textDecorationProperty.native](value: TextDecoration) {
|
||||
if (this.formattedText) {
|
||||
@@ -256,10 +131,11 @@ export class TextBase extends TextBaseCommon {
|
||||
}
|
||||
}
|
||||
|
||||
get [textTransformProperty.native](): string {
|
||||
return "none";
|
||||
//TextTransform
|
||||
get [textTransformProperty.native](): TextTransform {
|
||||
return TextTransform.NONE;
|
||||
}
|
||||
set [textTransformProperty.native](value: "none" | "capitalize" | "uppercase" | "lowercase") {
|
||||
set [textTransformProperty.native](value: TextTransform) {
|
||||
if (this.formattedText) {
|
||||
setFormattedTextDecorationAndTransform(this.formattedText, this.nativeView, this.style.textDecoration, value, this.style.letterSpacing);
|
||||
} else {
|
||||
@@ -267,21 +143,7 @@ export class TextBase extends TextBaseCommon {
|
||||
}
|
||||
}
|
||||
|
||||
// get [whiteSpaceProperty.native](): string {
|
||||
// return WhiteSpace.normal;
|
||||
// }
|
||||
// set [whiteSpaceProperty.native](value: string) {
|
||||
// let nativeView = this.nativeView;
|
||||
// if (value === WhiteSpace.normal) {
|
||||
// nativeView.lineBreakMode = NSLineBreakMode.ByWordWrapping;
|
||||
// nativeView.numberOfLines = 0;
|
||||
// }
|
||||
// else {
|
||||
// nativeView.lineBreakMode = NSLineBreakMode.ByTruncatingTail;
|
||||
// nativeView.numberOfLines = 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
// LetterSpacing
|
||||
get [letterSpacingProperty.native](): number {
|
||||
return Number.NaN;
|
||||
}
|
||||
@@ -292,20 +154,126 @@ export class TextBase extends TextBaseCommon {
|
||||
setTextDecorationAndTransform(this.text, this.nativeView, this.style.textDecoration, this.style.textTransform, value, this.style.color);
|
||||
}
|
||||
}
|
||||
|
||||
// private _settingFormattedTextPropertyToNative = false;
|
||||
// public _onStylePropertyChanged(property: dependencyObservable.Property): void {
|
||||
// if (this._settingFormattedTextPropertyToNative) {
|
||||
// // Guard against stack-overflow.
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (this.formattedText) {
|
||||
// // Re-apply the formatted text to override style changes if needed.
|
||||
// // https://github.com/NativeScript/NativeScript/issues/1078
|
||||
// this._settingFormattedTextPropertyToNative = true;
|
||||
// this._setFormattedTextPropertyToNative(this.formattedText);
|
||||
// this._settingFormattedTextPropertyToNative = false;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
export function getTransformedText(text: string, textTransform: TextTransform): string {
|
||||
switch (textTransform) {
|
||||
case TextTransform.NONE:
|
||||
return text;
|
||||
case TextTransform.UPPERCASE:
|
||||
return NSStringFromNSAttributedString(text).uppercaseString;
|
||||
case TextTransform.LOWERCASE:
|
||||
return NSStringFromNSAttributedString(text).lowercaseString;
|
||||
case TextTransform.CAPITALIZE:
|
||||
return NSStringFromNSAttributedString(text).capitalizedString;
|
||||
default:
|
||||
throw new Error(`Invalid text transform value: ${textTransform}. Valid values are: "${TextTransform.NONE}", "${TextTransform.CAPITALIZE}", "${TextTransform.UPPERCASE}, "${TextTransform.LOWERCASE}".`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function NSStringFromNSAttributedString(source: NSAttributedString | string): NSString {
|
||||
return NSString.stringWithString(source instanceof NSAttributedString && source.string || <string>source);
|
||||
}
|
||||
|
||||
function updateFormattedStringTextDecoration(formattedText: FormattedString, textDecoration: TextDecoration): void {
|
||||
// TODO: Refactor this method so it doesn't modify FormattedString properties.
|
||||
// Instead it should create NSAttributedString and apply it to the nativeView.
|
||||
switch(textDecoration) {
|
||||
case TextDecoration.NONE:
|
||||
formattedText.underline = NSUnderlineStyle.StyleNone;
|
||||
formattedText.strikethrough = NSUnderlineStyle.StyleNone;
|
||||
break;
|
||||
case TextDecoration.UNDERLINE:
|
||||
formattedText.underline = NSUnderlineStyle.StyleSingle;
|
||||
formattedText.strikethrough = NSUnderlineStyle.StyleNone;
|
||||
break;
|
||||
case TextDecoration.LINE_THROUGH:
|
||||
formattedText.underline = NSUnderlineStyle.StyleNone;
|
||||
formattedText.strikethrough = NSUnderlineStyle.StyleSingle;
|
||||
break;
|
||||
case TextDecoration.UNDERLINE_LINE_THROUGH:
|
||||
formattedText.underline = NSUnderlineStyle.StyleSingle;
|
||||
formattedText.strikethrough = NSUnderlineStyle.StyleSingle;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid text decoration value: ${textDecoration}. Valid values are: "${TextDecoration.NONE}", "${TextDecoration.UNDERLINE}", "${TextDecoration.LINE_THROUGH}", "${TextDecoration.UNDERLINE_LINE_THROUGH}".`);
|
||||
}
|
||||
}
|
||||
|
||||
function updateFormattedStringTextTransformation(formattedText: FormattedString, textTransform: TextTransform): void {
|
||||
// TODO: Refactor this method so it doesn't modify Span properties.
|
||||
// Instead it should create NSAttributedString and apply it to the nativeView.
|
||||
for (let i = 0, length = formattedText.spans.length; i < length; i++) {
|
||||
let span = formattedText.spans.getItem(i);
|
||||
span.text = getTransformedText(span.text, textTransform);
|
||||
}
|
||||
}
|
||||
|
||||
function setFormattedTextDecorationAndTransform(formattedText: FormattedString, nativeView: UITextField | UITextView | UILabel | UIButton, textDecoration: TextDecoration, textTransform: TextTransform, letterSpacing: number) {
|
||||
updateFormattedStringTextDecoration(formattedText, textDecoration);
|
||||
updateFormattedStringTextTransformation(formattedText, textTransform);
|
||||
|
||||
if (typeof letterSpacing === "number" && !isNaN(letterSpacing)) {
|
||||
if (nativeView instanceof UIButton) {
|
||||
let attrText = NSMutableAttributedString.alloc().initWithAttributedString(nativeView.attributedTitleForState(UIControlState.Normal));
|
||||
attrText.addAttributeValueRange(NSKernAttributeName, letterSpacing * nativeView.font.pointSize, { location: 0, length: attrText.length });
|
||||
nativeView.setAttributedTitleForState(attrText, UIControlState.Normal);
|
||||
} else {
|
||||
let attrText = NSMutableAttributedString.alloc().initWithAttributedString(nativeView.attributedText);
|
||||
attrText.addAttributeValueRange(NSKernAttributeName, letterSpacing * nativeView.font.pointSize, { location: 0, length: attrText.length });
|
||||
nativeView.attributedText = attrText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setTextDecorationAndTransform(text: string, nativeView: UITextField | UITextView | UILabel | UIButton, textDecoration: TextDecoration, textTransform: TextTransform, letterSpacing: number, color: Color) {
|
||||
let hasLetterSpacing = typeof letterSpacing === "number" && !isNaN(letterSpacing);
|
||||
|
||||
let dict = new Map<string, number>();
|
||||
switch(textDecoration) {
|
||||
case TextDecoration.NONE:
|
||||
break;
|
||||
case TextDecoration.UNDERLINE:
|
||||
dict.set(NSUnderlineStyleAttributeName, NSUnderlineStyle.StyleSingle);
|
||||
break;
|
||||
case TextDecoration.LINE_THROUGH:
|
||||
dict.set(NSStrikethroughStyleAttributeName, NSUnderlineStyle.StyleSingle);
|
||||
break;
|
||||
case TextDecoration.UNDERLINE_LINE_THROUGH:
|
||||
dict.set(NSUnderlineStyleAttributeName, NSUnderlineStyle.StyleSingle);
|
||||
dict.set(NSStrikethroughStyleAttributeName, NSUnderlineStyle.StyleSingle);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid text decoration value: ${textDecoration}. Valid values are: "${TextDecoration.NONE}", "${TextDecoration.UNDERLINE}", "${TextDecoration.LINE_THROUGH}", "${TextDecoration.UNDERLINE_LINE_THROUGH}".`);
|
||||
}
|
||||
|
||||
if (hasLetterSpacing) {
|
||||
dict.set(NSKernAttributeName, letterSpacing * nativeView.font.pointSize);
|
||||
}
|
||||
|
||||
if (color) {
|
||||
dict.set(NSForegroundColorAttributeName, color.ios);
|
||||
}
|
||||
|
||||
let source = getTransformedText(text, textTransform);
|
||||
if (dict.size > 0) {
|
||||
let result = NSMutableAttributedString.alloc().initWithString(source);
|
||||
result.setAttributesRange(<any>dict, { location: 0, length: source.length });
|
||||
if (nativeView instanceof UIButton) {
|
||||
nativeView.setAttributedTitleForState(result, UIControlState.Normal);
|
||||
} else {
|
||||
nativeView.attributedText = result;
|
||||
}
|
||||
} else {
|
||||
if (nativeView instanceof UIButton) {
|
||||
// Clear attributedText or title won't be affected.
|
||||
nativeView.setAttributedTitleForState(null, UIControlState.Normal);
|
||||
nativeView.setTitleForState(source, UIControlState.Normal);
|
||||
} else {
|
||||
// Clear attributedText or text won't be affected.
|
||||
nativeView.attributedText = undefined;
|
||||
nativeView.text = source;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,95 +5,6 @@ export * from "./utils-common";
|
||||
|
||||
// We are using "ad" here to avoid namespace collision with the global android object
|
||||
export module ad {
|
||||
|
||||
export function setTextDecoration(view: android.widget.TextView, value: string) {
|
||||
var flags = 0;
|
||||
|
||||
var values = (value + "").split(" ");
|
||||
|
||||
if (values.indexOf("underline") !== -1) {
|
||||
flags = flags | android.graphics.Paint.UNDERLINE_TEXT_FLAG;
|
||||
}
|
||||
|
||||
if (values.indexOf("line-through") !== -1) {
|
||||
flags = flags | android.graphics.Paint.STRIKE_THRU_TEXT_FLAG;
|
||||
}
|
||||
|
||||
if (values.indexOf("none") === -1) {
|
||||
view.setPaintFlags(flags);
|
||||
} else {
|
||||
view.setPaintFlags(0);
|
||||
}
|
||||
}
|
||||
|
||||
export function setTextTransform(v, value: string) {
|
||||
let view = v._nativeView;
|
||||
let str = view.getText() + "";
|
||||
let result = getTransformedString(value, view, str);
|
||||
|
||||
if (v.formattedText) {
|
||||
for (var i = 0; i < v.formattedText.spans.length; i++) {
|
||||
var span = v.formattedText.spans.getItem(i);
|
||||
span.text = getTransformedString(value, view, span.text);
|
||||
}
|
||||
} else {
|
||||
view.setText(result);
|
||||
}
|
||||
}
|
||||
|
||||
export function getTransformedString(textTransform: string, view, stringToTransform: string): string {
|
||||
let result: string;
|
||||
|
||||
switch (textTransform) {
|
||||
case "uppercase":
|
||||
view.setTransformationMethod(null);
|
||||
result = stringToTransform.toUpperCase();
|
||||
break;
|
||||
|
||||
case "lowercase":
|
||||
view.setTransformationMethod(null);
|
||||
result = stringToTransform.toLowerCase();
|
||||
break;
|
||||
|
||||
case "capitalize":
|
||||
view.setTransformationMethod(null);
|
||||
result = getCapitalizedString(stringToTransform);
|
||||
break;
|
||||
|
||||
case "none":
|
||||
default:
|
||||
result = view["originalString"] || stringToTransform;
|
||||
if (view["transformationMethod"]) {
|
||||
view.setTransformationMethod(view["transformationMethod"]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!view["originalString"]) {
|
||||
view["originalString"] = stringToTransform;
|
||||
view["transformationMethod"] = view.getTransformationMethod();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getCapitalizedString(str: string): string {
|
||||
var words = str.split(" ");
|
||||
var newWords = [];
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
let word = words[i].toLowerCase();
|
||||
newWords.push(word.substr(0, 1).toUpperCase() + word.substring(1));
|
||||
}
|
||||
|
||||
return newWords.join(" ");
|
||||
}
|
||||
|
||||
export function setWhiteSpace(view: android.widget.TextView, value: string) {
|
||||
let nowrap = value === "nowrap";
|
||||
view.setSingleLine(nowrap);
|
||||
view.setEllipsize(nowrap ? android.text.TextUtils.TruncateAt.END : null);
|
||||
}
|
||||
|
||||
let nativeApp: android.app.Application;
|
||||
declare var com;
|
||||
export function getApplication() {
|
||||
|
||||
8
tns-core-modules/utils/utils.d.ts
vendored
8
tns-core-modules/utils/utils.d.ts
vendored
@@ -78,11 +78,6 @@
|
||||
* Module with android specific utilities.
|
||||
*/
|
||||
module ad {
|
||||
export function setTextTransform(view, value: string);
|
||||
export function setWhiteSpace(view, value: string);
|
||||
export function setTextDecoration(view, value: string);
|
||||
export function getTransformedString(textTransform: string, view, stringToTransform: string): string;
|
||||
|
||||
/**
|
||||
* Gets the native Android application instance.
|
||||
*/
|
||||
@@ -163,9 +158,6 @@
|
||||
* Example: getter(NSRunLoop, NSRunLoop.currentRunLoop).runUntilDate(NSDate.dateWithTimeIntervalSinceNow(waitTime));
|
||||
*/
|
||||
export function getter<T>(_this: any, propertyValue: T | {(): T}): T;
|
||||
export function getTransformedText(view, source: string, transform: string): string;
|
||||
export function setWhiteSpace(view, value: string, parentView?: any);
|
||||
export function setTextAlignment(view, value: string);
|
||||
|
||||
// Common properties between UILabel, UITextView and UITextField
|
||||
export interface TextUIView {
|
||||
|
||||
@@ -34,22 +34,6 @@ export module layout {
|
||||
}
|
||||
|
||||
export module ios {
|
||||
export function setTextAlignment(view: dts.ios.TextUIView, value: string) {
|
||||
switch (value) {
|
||||
case "left":
|
||||
view.textAlignment = NSTextAlignment.Left;
|
||||
break;
|
||||
case "center":
|
||||
view.textAlignment = NSTextAlignment.Center;
|
||||
break;
|
||||
case "right":
|
||||
view.textAlignment = NSTextAlignment.Right;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export function getter<T>(_this: any, property: T | { (): T }): T {
|
||||
if (typeof property === "function") {
|
||||
return (<{ (): T }>property).call(_this);
|
||||
@@ -58,50 +42,6 @@ export module ios {
|
||||
}
|
||||
}
|
||||
|
||||
export function getTransformedText(view, source: string, transform: string): string {
|
||||
let result = source;
|
||||
|
||||
switch (transform) {
|
||||
case "uppercase":
|
||||
result = NSStringFromNSAttributedString(source).uppercaseString;
|
||||
break;
|
||||
|
||||
case "lowercase":
|
||||
result = NSStringFromNSAttributedString(source).lowercaseString;
|
||||
break;
|
||||
|
||||
case "capitalize":
|
||||
result = NSStringFromNSAttributedString(source).capitalizedString;
|
||||
break;
|
||||
|
||||
case "none":
|
||||
default:
|
||||
result = view.text;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function NSStringFromNSAttributedString(source: NSAttributedString | string): NSString {
|
||||
return NSString.stringWithString(source instanceof NSAttributedString && source.string || <string>source);
|
||||
}
|
||||
|
||||
export function setWhiteSpace(view: dts.ios.TextUIView, value: string, parentView?: UIView) {
|
||||
if (value === "normal") {
|
||||
view.lineBreakMode = NSLineBreakMode.ByWordWrapping;
|
||||
view.numberOfLines = 0;
|
||||
}
|
||||
else {
|
||||
if (parentView) {
|
||||
view.lineBreakMode = NSLineBreakMode.ByTruncatingMiddle;
|
||||
} else {
|
||||
view.lineBreakMode = NSLineBreakMode.ByTruncatingTail;
|
||||
}
|
||||
view.numberOfLines = 1;
|
||||
}
|
||||
}
|
||||
|
||||
export module collections {
|
||||
export function jsArrayToNSArray(str: string[]): NSArray<any> {
|
||||
return NSArray.arrayWithArray(<any>str);
|
||||
|
||||
Reference in New Issue
Block a user