mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-17 04:41:36 +08:00
Refactor formatted text
This commit is contained in:
16
tests/.vscode/launch.json
vendored
16
tests/.vscode/launch.json
vendored
@ -11,7 +11,8 @@
|
||||
"diagnosticLogging": false,
|
||||
"emulator": false,
|
||||
"rebuild": false,
|
||||
"syncAllFiles": false
|
||||
"syncAllFiles": true,
|
||||
"stopOnEntry": true
|
||||
},
|
||||
{
|
||||
"name": "Launch on iOS",
|
||||
@ -22,7 +23,8 @@
|
||||
"sourceMaps": true,
|
||||
"diagnosticLogging": false,
|
||||
"emulator": false,
|
||||
"rebuild": true
|
||||
"rebuild": true,
|
||||
"stopOnEntry": true
|
||||
},
|
||||
{
|
||||
"name": "Attach on iOS",
|
||||
@ -32,7 +34,8 @@
|
||||
"appRoot": "${workspaceRoot}",
|
||||
"sourceMaps": true,
|
||||
"diagnosticLogging": false,
|
||||
"emulator": false
|
||||
"emulator": false,
|
||||
"stopOnEntry": true
|
||||
},
|
||||
{
|
||||
"name": "Sync on Android",
|
||||
@ -44,6 +47,7 @@
|
||||
"diagnosticLogging": false,
|
||||
"emulator": false,
|
||||
"rebuild": false,
|
||||
"syncAllFiles": true,
|
||||
"stopOnEntry": true
|
||||
},
|
||||
{
|
||||
@ -55,7 +59,8 @@
|
||||
"sourceMaps": true,
|
||||
"diagnosticLogging": false,
|
||||
"emulator": false,
|
||||
"rebuild": true
|
||||
"rebuild": true,
|
||||
"stopOnEntry": true
|
||||
},
|
||||
{
|
||||
"name": "Attach on Android",
|
||||
@ -65,7 +70,8 @@
|
||||
"appRoot": "${workspaceRoot}",
|
||||
"sourceMaps": true,
|
||||
"diagnosticLogging": false,
|
||||
"emulator": false
|
||||
"emulator": false,
|
||||
"stopOnEntry": true
|
||||
}
|
||||
]
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
import { FormattedStringBase } from "./formatted-string-common";
|
||||
import { toUIString } from "utils/types";
|
||||
|
||||
export * from "./formatted-string-common";
|
||||
|
||||
export class FormattedString extends FormattedStringBase {
|
||||
public createFormattedStringCore() {
|
||||
let ssb = new android.text.SpannableStringBuilder();
|
||||
|
||||
for (let i = 0, spanStart = 0, spanLength = 0, spanText = "", length = this.spans.length; i < length; i++) {
|
||||
let span = this.spans.getItem(i);
|
||||
spanText = toUIString(span.text);
|
||||
spanLength = spanText.length;
|
||||
if (spanLength !== 0) {
|
||||
ssb.insert(spanStart, spanText);
|
||||
span.updateSpanModifiers(this);
|
||||
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;
|
||||
}
|
||||
}
|
||||
this._formattedText = ssb;
|
||||
}
|
||||
|
||||
public _updateCharactersInRangeReplacementString(rangeLocation: number, rangeLength: number, replacementString: string): void {
|
||||
//
|
||||
}
|
||||
}
|
6
tns-core-modules/text/formatted-string.d.ts
vendored
6
tns-core-modules/text/formatted-string.d.ts
vendored
@ -98,11 +98,5 @@ declare module "text/formatted-string" {
|
||||
* A static method used to add child elements of the FormattedString class to a View declared in xml.
|
||||
*/
|
||||
public static addFormattedStringToView(view: FormattedStringView, name: string, value: any): void;
|
||||
|
||||
//@private
|
||||
createFormattedStringCore(): void;
|
||||
_updateCharactersInRangeReplacementString(rangeLocation: number, rangeLength: number, replacementString: string): void;
|
||||
_formattedText: any;
|
||||
//@endprivate
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
import { FormattedStringBase } from "./formatted-string-common";
|
||||
import { toUIString } from "utils/types";
|
||||
|
||||
export * from "./formatted-string-common";
|
||||
|
||||
export class FormattedString extends FormattedStringBase {
|
||||
public createFormattedStringCore() {
|
||||
let mas = NSMutableAttributedString.alloc().init();
|
||||
for (let i = 0, spanStart = 0, spanLength = 0, length = this.spans.length, spanText = ""; i < length; i++) {
|
||||
let span = this.spans.getItem(i);
|
||||
spanText = toUIString(span.text);
|
||||
spanLength = spanText.length;
|
||||
span.updateSpanModifiers(this);
|
||||
let attrDict = NSMutableDictionary.alloc<string, any>().init();
|
||||
for (let p = 0; p < span.spanModifiers.length; p++) {
|
||||
attrDict.setObjectForKey(span.spanModifiers[p].value, span.spanModifiers[p].key);
|
||||
}
|
||||
let nsAttributedString = NSMutableAttributedString.alloc().initWithStringAttributes(String(spanText), attrDict);
|
||||
mas.insertAttributedStringAtIndex(nsAttributedString, spanStart);
|
||||
spanStart += spanLength;
|
||||
}
|
||||
this._formattedText = mas;
|
||||
}
|
||||
|
||||
public _updateCharactersInRangeReplacementString(rangeLocation: number, rangeLength: number, replacementString: string): void {
|
||||
let deletingText = !replacementString;
|
||||
let currentLocation = 0;
|
||||
for (let i = 0, length = this.spans.length; i < length; i++) {
|
||||
let span = this.spans.getItem(i);
|
||||
if (currentLocation <= rangeLocation && rangeLocation < (currentLocation + span.text.length)){
|
||||
let newText = splice(span.text, rangeLocation - currentLocation, deletingText ? rangeLength : 0, replacementString);
|
||||
span._setTextInternal(newText);
|
||||
return;
|
||||
}
|
||||
currentLocation += span.text.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @param {String} value The string to splice.
|
||||
* @param {number} start Index at which to start changing the string.
|
||||
* @param {number} delCount An integer indicating the number of old chars to remove.
|
||||
* @param {string} newSubStr The String that is spliced in.
|
||||
* @return {string} A new string with the spliced substring.function splice(value: string, start: number, delCount: number, newSubStr: string) {
|
||||
*/
|
||||
function splice(value: string, start: number, delCount: number, newSubStr: string) {
|
||||
return value.slice(0, start) + newSubStr + value.slice(start + Math.abs(delCount));
|
||||
}
|
@ -14,9 +14,8 @@ const CHILD_SPAN = "Span";
|
||||
const CHILD_FORMATTED_TEXT = "formattedText";
|
||||
const CHILD_FORMATTED_STRING = "FormattedString";
|
||||
|
||||
export abstract class FormattedStringBase extends Observable implements FormattedStringDefinition, AddArrayFromBuilder, AddChildFromBuilder {
|
||||
export class FormattedString extends Observable implements FormattedStringDefinition, AddArrayFromBuilder, AddChildFromBuilder {
|
||||
private _spans: ObservableArray<Span>;
|
||||
private _isDirty: boolean;
|
||||
private _fontFamily: string;
|
||||
private _fontSize: number;
|
||||
private _foregroundColor: Color;
|
||||
@ -25,6 +24,7 @@ export abstract class FormattedStringBase extends Observable implements Formatte
|
||||
private _strikethrough: number;
|
||||
private _fontAttributes: number;
|
||||
private _parent: View;
|
||||
private _dummyPropertyChangedData: PropertyChangeData;
|
||||
|
||||
public _formattedText: any;
|
||||
|
||||
@ -32,7 +32,7 @@ export abstract class FormattedStringBase extends Observable implements Formatte
|
||||
super();
|
||||
this._spans = new ObservableArray<Span>();
|
||||
this._spans.addEventListener(ObservableArray.changeEvent, this.onSpansCollectionChanged, this);
|
||||
this._isDirty = true;
|
||||
this._dummyPropertyChangedData = this._createPropertyChangeData("", this);
|
||||
}
|
||||
|
||||
get parent(): View {
|
||||
@ -149,10 +149,6 @@ export abstract class FormattedStringBase extends Observable implements Formatte
|
||||
return this._spans;
|
||||
}
|
||||
|
||||
public abstract createFormattedStringCore(): void;
|
||||
|
||||
public abstract _updateCharactersInRangeReplacementString(rangeLocation: number, rangeLength: number, replacementString: string): void;
|
||||
|
||||
public toString(): string {
|
||||
let result = "";
|
||||
for (let i = 0, length = this._spans.length; i < length; i++) {
|
||||
@ -212,19 +208,10 @@ export abstract class FormattedStringBase extends Observable implements Formatte
|
||||
removedSpan.removeEventListener(Observable.propertyChangeEvent, this.onSpanChanged, this);
|
||||
}
|
||||
}
|
||||
this.updateFormattedText(true);
|
||||
this.notify(this._dummyPropertyChangedData);
|
||||
}
|
||||
|
||||
private onSpanChanged(eventData: PropertyChangeData) {
|
||||
this.updateFormattedText(true);
|
||||
}
|
||||
|
||||
private updateFormattedText(isDirty?: boolean) {
|
||||
let shouldUpdate = isDirty || this._isDirty;
|
||||
if (shouldUpdate) {
|
||||
this.createFormattedStringCore();
|
||||
this._isDirty = false;
|
||||
this.notify(this._createPropertyChangeData("", this));
|
||||
}
|
||||
this.notify(this._dummyPropertyChangedData);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
declare module "ui/editable-text-base" {
|
||||
import { TextBase, Property, CssProperty, Style, Color } from "ui/text-base";
|
||||
import { TextBase, Property, CssProperty, Style, Color, FormattedString } from "ui/text-base";
|
||||
|
||||
export const keyboardTypeProperty: Property<EditableTextBase, string>;
|
||||
export const returnKeyTypeProperty: Property<EditableTextBase, string>;
|
||||
@ -56,5 +56,9 @@
|
||||
dismissSoftInput(): void;
|
||||
}
|
||||
|
||||
//@private
|
||||
export function _updateCharactersInRangeReplacementString(formattedText: FormattedString, rangeLocation: number, rangeLength: number, replacementString: string): void;
|
||||
//@endprivate
|
||||
|
||||
export * from "ui/text-base";
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import {
|
||||
EditableTextBase as EditableTextBaseCommon, keyboardTypeProperty,
|
||||
returnKeyTypeProperty,
|
||||
autocapitalizationTypeProperty, autocorrectProperty
|
||||
autocapitalizationTypeProperty, autocorrectProperty, FormattedString
|
||||
} from "./editable-text-base-common";
|
||||
|
||||
export * from "./editable-text-base-common";
|
||||
@ -185,4 +185,29 @@ export abstract class EditableTextBase extends EditableTextBaseCommon {
|
||||
|
||||
this.nativeView.autocorrectionType = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function _updateCharactersInRangeReplacementString(formattedText: FormattedString, rangeLocation: number, rangeLength: number, replacementString: string): void {
|
||||
let deletingText = !replacementString;
|
||||
let currentLocation = 0;
|
||||
for (let i = 0, length = formattedText.spans.length; i < length; i++) {
|
||||
let span = formattedText.spans.getItem(i);
|
||||
if (currentLocation <= rangeLocation && rangeLocation < (currentLocation + span.text.length)){
|
||||
let newText = splice(span.text, rangeLocation - currentLocation, deletingText ? rangeLength : 0, replacementString);
|
||||
span._setTextInternal(newText);
|
||||
return;
|
||||
}
|
||||
currentLocation += span.text.length;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @param {String} value The string to splice.
|
||||
* @param {number} start Index at which to start changing the string.
|
||||
* @param {number} delCount An integer indicating the number of old chars to remove.
|
||||
* @param {string} newSubStr The String that is spliced in.
|
||||
* @return {string} A new string with the spliced substring.function splice(value: string, start: number, delCount: number, newSubStr: string) {
|
||||
*/
|
||||
function splice(value: string, start: number, delCount: number, newSubStr: string) {
|
||||
return value.slice(0, start) + newSubStr + value.slice(start + Math.abs(delCount));
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export * from "ui/core/view";
|
||||
|
||||
export abstract class TextBaseCommon extends View implements TextBaseDefinition, FormattedStringView {
|
||||
|
||||
public abstract _setFormattedTextPropertyToNative(value: FormattedString): void;
|
||||
// public abstract _setFormattedTextPropertyToNative(value: FormattedString): void;
|
||||
|
||||
public text: string;
|
||||
public formattedText: FormattedString;
|
||||
@ -91,10 +91,11 @@ export abstract class TextBaseCommon extends View implements TextBaseDefinition,
|
||||
this.style.paddingLeft = value;
|
||||
}
|
||||
|
||||
public onFormattedTextChanged(data: PropertyChangeData) {
|
||||
let value = data.value;
|
||||
this._setFormattedTextPropertyToNative(value);
|
||||
textProperty.nativeValueChange(this, value.toString());
|
||||
public _onFormattedTextContentsChanged(data: PropertyChangeData) {
|
||||
if (this._nativeView){
|
||||
// Notifications from the FormattedString start arriving before the Android view is even created.
|
||||
this[formattedTextProperty.native] = data.value;
|
||||
}
|
||||
}
|
||||
|
||||
public _addChildFromBuilder(name: string, value: any): void {
|
||||
@ -125,12 +126,12 @@ formattedTextProperty.register(TextBaseCommon);
|
||||
function onFormattedTextPropertyChanged(textBase: TextBaseCommon, oldValue: FormattedString, newValue: FormattedString) {
|
||||
if (oldValue) {
|
||||
oldValue.parent = null;
|
||||
removeWeakEventListener(oldValue, Observable.propertyChangeEvent, textBase.onFormattedTextChanged, textBase);
|
||||
removeWeakEventListener(oldValue, Observable.propertyChangeEvent, textBase._onFormattedTextContentsChanged, textBase);
|
||||
}
|
||||
|
||||
if (newValue) {
|
||||
newValue.parent = textBase;
|
||||
addWeakEventListener(newValue, Observable.propertyChangeEvent, textBase.onFormattedTextChanged, textBase);
|
||||
addWeakEventListener(newValue, Observable.propertyChangeEvent, textBase._onFormattedTextContentsChanged, textBase);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,19 +4,13 @@
|
||||
Font, Color, FormattedString, TextDecoration, TextAlignment, TextTransform, WhiteSpace,
|
||||
paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, Length
|
||||
} from "./text-base-common";
|
||||
import { toUIString } from "utils/types";
|
||||
|
||||
export * from "./text-base-common";
|
||||
export class TextBase extends TextBaseCommon {
|
||||
_transformationMethod: any;
|
||||
_nativeView: android.widget.TextView;
|
||||
|
||||
public _setFormattedTextPropertyToNative(value: FormattedString) {
|
||||
if (this._nativeView) {
|
||||
let newText = value ? value._formattedText : this.text;
|
||||
this._nativeView.setText(newText);
|
||||
}
|
||||
}
|
||||
|
||||
//Text
|
||||
get [textProperty.native](): string {
|
||||
return this._nativeView.getText();
|
||||
@ -31,7 +25,31 @@ export class TextBase extends TextBaseCommon {
|
||||
return null;
|
||||
}
|
||||
set [formattedTextProperty.native](value: FormattedString) {
|
||||
this._setFormattedTextPropertyToNative(value);
|
||||
let spannableStringBuilder = createSpannableStringBuilder(value);
|
||||
const text = (spannableStringBuilder === null || spannableStringBuilder === undefined) ? '' : <any>spannableStringBuilder;
|
||||
this._nativeView.setText(text);
|
||||
|
||||
if (spannableStringBuilder && this._nativeView instanceof android.widget.Button &&
|
||||
!(this._nativeView.getTransformationMethod() instanceof TextTransformation)){
|
||||
// Replace Android Button's default transformation (in case the developer has not already specified a text-transform) method
|
||||
// with our transformation method which can handle formatted text.
|
||||
// Otherwise, the default tranformation method of the Android Button will overwrite and ignore our spannableStringBuilder.
|
||||
// We can't set it to NONE since it is the default value. Set it to something else first.
|
||||
this.style[textTransformProperty.cssName] = TextTransform.UPPERCASE;
|
||||
this.style[textTransformProperty.cssName] = TextTransform.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
//TextTransform
|
||||
get [textTransformProperty.native](): android.text.method.TransformationMethod {
|
||||
return this._nativeView.getTransformationMethod();
|
||||
}
|
||||
set [textTransformProperty.native](value: TextTransform | android.text.method.TransformationMethod) {
|
||||
if (typeof value === "string") {
|
||||
this._nativeView.setTransformationMethod(new TextTransformation(this.text, this.formattedText, value));
|
||||
} else {
|
||||
this._nativeView.setTransformationMethod(value);
|
||||
}
|
||||
}
|
||||
|
||||
//Color
|
||||
@ -128,18 +146,6 @@ export class TextBase extends TextBaseCommon {
|
||||
this._nativeView.setPaintFlags(flags);
|
||||
}
|
||||
|
||||
//TextTransform
|
||||
get [textTransformProperty.native](): android.text.method.TransformationMethod {
|
||||
return this._nativeView.getTransformationMethod();
|
||||
}
|
||||
set [textTransformProperty.native](value: TextTransform | android.text.method.TransformationMethod) {
|
||||
if (typeof value === "string") {
|
||||
this._nativeView.setTransformationMethod(new TextTransformation(this.text, this.formattedText, value));
|
||||
} else {
|
||||
this._nativeView.setTransformationMethod(value);
|
||||
}
|
||||
}
|
||||
|
||||
//WhiteSpace
|
||||
get [whiteSpaceProperty.native](): WhiteSpace {
|
||||
return WhiteSpace.NORMAL;
|
||||
@ -208,45 +214,31 @@ class TextTransformation extends android.text.method.ReplacementTransformationMe
|
||||
}
|
||||
|
||||
protected getOriginal(): native.Array<string> {
|
||||
let result: native.Array<string> = [];
|
||||
if (this.formattedText && this.formattedText._formattedText) {
|
||||
for (let i = 0, loopLength = this.formattedText._formattedText.length(); i < loopLength; i++) {
|
||||
result[i] = this.formattedText._formattedText.charAt(i);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0, loopLength = this.originalText.length; i < loopLength; i++) {
|
||||
result[i] = this.originalText.charAt(i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private _getTransformedString(): string {
|
||||
let stringResult: 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);
|
||||
stringResult += getTransformedText(span.text, textTransform);
|
||||
}
|
||||
}
|
||||
else {
|
||||
stringResult = getTransformedText(this.originalText, textTransform);
|
||||
}
|
||||
return stringResult;
|
||||
return convertStringToNativeCharArray(this.formattedText ? this.formattedText.toString() : this.originalText);
|
||||
}
|
||||
|
||||
protected getReplacement(): native.Array<string> {
|
||||
let transformedString = this._getTransformedString();
|
||||
let result: native.Array<string> = [];
|
||||
for (let i = 0, length = transformedString.length; i < length; i++) {
|
||||
result[i] = transformedString.charAt(i);
|
||||
let replacementString: string = "";
|
||||
if (this.formattedText) {
|
||||
for (let i = 0, length = this.formattedText.spans.length; i < length; i++) {
|
||||
let span = this.formattedText.spans.getItem(i);
|
||||
replacementString += getTransformedText(span.text, this.textTransform);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
else {
|
||||
replacementString = getTransformedText(this.originalText, this.textTransform);
|
||||
}
|
||||
|
||||
return convertStringToNativeCharArray(replacementString);
|
||||
}
|
||||
|
||||
public getTransformation(charSeq: string, view: android.view.View): string {
|
||||
return this._getTransformedString();
|
||||
public getTransformation(charSeq: any, view: android.view.View): any {
|
||||
if (this.formattedText) {
|
||||
return createSpannableStringBuilder(this.formattedText);
|
||||
}
|
||||
else {
|
||||
return getTransformedText(this.originalText, this.textTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,7 +253,7 @@ function getCapitalizedString(str: string): string {
|
||||
return newWords.join(" ");
|
||||
}
|
||||
|
||||
export function getTransformedText(text: string, textTransform: TextTransform): string {
|
||||
function getTransformedText(text: string, textTransform: TextTransform): string {
|
||||
switch (textTransform) {
|
||||
case TextTransform.NONE:
|
||||
return text;
|
||||
@ -274,4 +266,42 @@ export function getTransformedText(text: string, textTransform: TextTransform):
|
||||
default:
|
||||
throw new Error(`Invalid text transform value: ${textTransform}. Valid values are: "${TextTransform.NONE}", "${TextTransform.CAPITALIZE}", "${TextTransform.UPPERCASE}", "${TextTransform.LOWERCASE}".`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createSpannableStringBuilder(formattedString: FormattedString): android.text.SpannableStringBuilder {
|
||||
let ssb = new android.text.SpannableStringBuilder();
|
||||
|
||||
if (formattedString === null || formattedString === undefined){
|
||||
return ssb;
|
||||
}
|
||||
|
||||
for (let i = 0, spanStart = 0, spanLength = 0, spanText = "", length = formattedString.spans.length; i < length; i++) {
|
||||
let span = formattedString.spans.getItem(i);
|
||||
spanText = toUIString(span.text);
|
||||
if (formattedString.parent){
|
||||
let textTransform = (<TextBase>formattedString.parent).textTransform;
|
||||
if (textTransform){
|
||||
spanText = getTransformedText(spanText, textTransform);
|
||||
}
|
||||
}
|
||||
spanLength = spanText.length;
|
||||
if (spanLength !== 0) {
|
||||
ssb.insert(spanStart, spanText);
|
||||
span.updateSpanModifiers(formattedString);
|
||||
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;
|
||||
}
|
||||
}
|
||||
return ssb;
|
||||
}
|
||||
|
||||
function convertStringToNativeCharArray(value: string): native.Array<string> {
|
||||
let nativeCharArray: native.Array<string> = [];
|
||||
|
||||
for (let i = 0, length = value.length; i < length; i++) {
|
||||
nativeCharArray[i] = value.charAt(i);
|
||||
}
|
||||
return nativeCharArray;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
TextDecoration, TextAlignment, TextTransform
|
||||
} from "./text-base-common";
|
||||
import * as utils from "utils/utils";
|
||||
import { toUIString } from "utils/types";
|
||||
|
||||
export * from "./text-base-common";
|
||||
|
||||
@ -32,7 +33,8 @@ export class TextBase extends TextBaseCommon {
|
||||
let style = this.style;
|
||||
setTextDecorationAndTransform(newValue, this.nativeView, style.textDecoration, style.textTransform, style.letterSpacing, style.color);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
nativeView.text = newValue;
|
||||
}
|
||||
this._requestLayoutOnTextChanged();
|
||||
@ -43,16 +45,12 @@ export class TextBase extends TextBaseCommon {
|
||||
return null;
|
||||
}
|
||||
set [formattedTextProperty.native](value: FormattedString) {
|
||||
this._setFormattedTextPropertyToNative(value);
|
||||
}
|
||||
|
||||
public _setFormattedTextPropertyToNative(value: FormattedString) {
|
||||
let newText = value ? value._formattedText : null;
|
||||
let mas = createNSMutableAttributedString(value);
|
||||
let nativeView = this.nativeView;
|
||||
if (nativeView instanceof UIButton) {
|
||||
nativeView.setAttributedTitleForState(newText, UIControlState.Normal);
|
||||
nativeView.setAttributedTitleForState(mas, UIControlState.Normal);
|
||||
} else {
|
||||
nativeView.attributedText = newText;
|
||||
nativeView.attributedText = mas;
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,3 +278,21 @@ function setTextDecorationAndTransform(text: string, nativeView: UITextField | U
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createNSMutableAttributedString(formattedString: FormattedString): NSMutableAttributedString {
|
||||
let mas = NSMutableAttributedString.alloc().init();
|
||||
for (let i = 0, spanStart = 0, spanLength = 0, length = formattedString.spans.length, spanText = ""; i < length; i++) {
|
||||
let span = formattedString.spans.getItem(i);
|
||||
spanText = toUIString(span.text);
|
||||
spanLength = spanText.length;
|
||||
span.updateSpanModifiers(formattedString);
|
||||
let attrDict = NSMutableDictionary.alloc<string, any>().init();
|
||||
for (let p = 0; p < span.spanModifiers.length; p++) {
|
||||
attrDict.setObjectForKey(span.spanModifiers[p].value, span.spanModifiers[p].key);
|
||||
}
|
||||
let nsAttributedString = NSMutableAttributedString.alloc().initWithStringAttributes(String(spanText), attrDict);
|
||||
mas.insertAttributedStringAtIndex(nsAttributedString, spanStart);
|
||||
spanStart += spanLength;
|
||||
}
|
||||
return mas;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {
|
||||
TextFieldBase, Color, secureProperty, textProperty, hintProperty, colorProperty, placeholderColorProperty,
|
||||
Length, paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty
|
||||
Length, paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty, _updateCharactersInRangeReplacementString
|
||||
} from "./text-field-common";
|
||||
|
||||
export * from "./text-field-common";
|
||||
@ -41,9 +41,9 @@ class UITextFieldDelegateImpl extends NSObject implements UITextFieldDelegate {
|
||||
|
||||
owner.dismissSoftInput();
|
||||
|
||||
if (owner.formattedText) {
|
||||
owner.formattedText.createFormattedStringCore();
|
||||
}
|
||||
// if (owner.formattedText) {
|
||||
// formattedTextProperty.nativeValueChange(owner, textField.attributedText);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ class UITextFieldDelegateImpl extends NSObject implements UITextFieldDelegate {
|
||||
if (owner) {
|
||||
if (owner.updateTextTrigger === "textChanged") {
|
||||
if (textField.secureTextEntry && this.firstEdit) {
|
||||
textProperty.nativeValueChange(owner, replacementString);
|
||||
textProperty.nativeValueChange(owner, replacementString);
|
||||
}
|
||||
else {
|
||||
if (range.location <= textField.text.length) {
|
||||
@ -84,7 +84,7 @@ class UITextFieldDelegateImpl extends NSObject implements UITextFieldDelegate {
|
||||
}
|
||||
|
||||
if (owner.formattedText) {
|
||||
owner.formattedText._updateCharactersInRangeReplacementString(range.location, range.length, replacementString);
|
||||
_updateCharactersInRangeReplacementString(owner.formattedText, range.location, range.length, replacementString);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
import {
|
||||
EditableTextBase, editableProperty, hintProperty, textProperty, colorProperty,
|
||||
borderTopWidthProperty, borderRightWidthProperty, borderBottomWidthProperty, borderLeftWidthProperty,
|
||||
paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty, Length
|
||||
paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty, Length, _updateCharactersInRangeReplacementString
|
||||
|
||||
} from "ui/editable-text-base";
|
||||
import { Color } from "color";
|
||||
@ -40,10 +40,9 @@ class UITextViewDelegateImpl extends NSObject implements UITextViewDelegate {
|
||||
owner.dismissSoftInput();
|
||||
owner._refreshHintState(owner.hint, textView.text);
|
||||
|
||||
if (owner.formattedText) {
|
||||
owner.formattedText.createFormattedStringCore();
|
||||
|
||||
}
|
||||
// if (owner.formattedText) {
|
||||
// formattedTextProperty.nativeValueChange(owner, textView.attributedText);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +58,7 @@ class UITextViewDelegateImpl extends NSObject implements UITextViewDelegate {
|
||||
public textViewShouldChangeTextInRangeReplacementText(textView: UITextView, range: NSRange, replacementString: string): boolean {
|
||||
const owner = this._owner.get();
|
||||
if (owner && owner.formattedText) {
|
||||
owner.formattedText._updateCharactersInRangeReplacementString(range.location, range.length, replacementString);
|
||||
_updateCharactersInRangeReplacementString(owner.formattedText, range.location, range.length, replacementString);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
Reference in New Issue
Block a user