mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-16 03:31:45 +08:00
fix span (#3510)
* Remove Bindable. Fix Observable & ObservableArray tests Fix formattedString text Change implementation of Span, FormattedString & TextBase properties valueChange called before native setter * revetred formattedString tests asserts - formattedText update text property again properties - when getting value we now use always property name instead of key (using key could return undefined for property that is set to its default value) updated fontSize & fontInternal properties on all controls fix font properties so that fontInternal is reset if the new font is the same as Font.default * fix tslint errors
This commit is contained in:
@ -1,53 +1,52 @@
|
||||
import * as TKUnit from "../TKUnit";
|
||||
import { ViewBase } from "ui/core/view-base";
|
||||
require("globals");
|
||||
import { Label } from "ui/label";
|
||||
|
||||
// >> observable-array-require
|
||||
import * as observableArrayModule from "data/observable-array";
|
||||
import { ObservableArray, ChangedData, ChangeType } from "data/observable-array";
|
||||
// << observable-array-require
|
||||
|
||||
require("globals");
|
||||
|
||||
export const test_ObservableArray_shouldCopySourceArrayItems = function () {
|
||||
// >> observable-array-create
|
||||
const sa = [1, 2, 3];
|
||||
const array = new observableArrayModule.ObservableArray(sa);
|
||||
const array = new ObservableArray(sa);
|
||||
// << observable-array-create
|
||||
|
||||
TKUnit.assert(sa.length === array.length && array.length === 3, "ObservableArray should copy all source array items!");
|
||||
TKUnit.assertEqual(array.length, 3, "ObservableArray length should be 3");
|
||||
TKUnit.assertEqual(sa.length, array.length, "ObservableArray should copy all source array items!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_shouldCopyMultipleItemsAsSource = function () {
|
||||
// >> observable-array-arguments
|
||||
const array = new observableArrayModule.ObservableArray(1, 2, 3);
|
||||
const array = new ObservableArray(1, 2, 3);
|
||||
// << observable-array-arguments
|
||||
|
||||
TKUnit.assert(array.length === 3 && array.getItem(1) === 2, "ObservableArray should copy multiple items from source!");
|
||||
TKUnit.assertEqual(array.length, 3, "ObservableArray length should be 3");
|
||||
TKUnit.assertEqual(array.getItem(1), 2, "ObservableArray should copy multiple items from source!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_shouldCreateArrayFromSpecifiedLength = function () {
|
||||
// >> observable-array-length
|
||||
const array = new observableArrayModule.ObservableArray(100);
|
||||
const array = new ObservableArray(100);
|
||||
// << observable-array-length
|
||||
|
||||
TKUnit.assert(array.length === 100, "ObservableArray should create array from specified length!");
|
||||
TKUnit.assertEqual(array.length, 100, "ObservableArray should create array from specified length!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_shouldBeAbleToSetLength = function () {
|
||||
// >> observable-array-newvalue
|
||||
const array = new observableArrayModule.ObservableArray(100);
|
||||
const array = new ObservableArray(100);
|
||||
// >> (hide)
|
||||
TKUnit.assert(array.length === 100, "ObservableArray should create array from specified length!");
|
||||
TKUnit.assertEqual(array.length, 100, "ObservableArray should create array from specified length!");
|
||||
// << (hide)
|
||||
array.length = 50;
|
||||
// << observable-array-newvalue
|
||||
|
||||
TKUnit.assert(array.length === 50, "ObservableArray should respect new length!");
|
||||
TKUnit.assertEqual(array.length, 50, "ObservableArray should respect new length!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_getItemShouldReturnCorrectItem = function () {
|
||||
// >> observable-array-getitem
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
const firstItem = array.getItem(0);
|
||||
const secondItem = array.getItem(1);
|
||||
const thirdItem = array.getItem(2);
|
||||
@ -58,7 +57,7 @@ export const test_ObservableArray_getItemShouldReturnCorrectItem = function () {
|
||||
|
||||
export const test_ObservableArray_setItemShouldSetCorrectItem = function () {
|
||||
// >> observable-array-setitem
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
array.setItem(1, 5);
|
||||
// << observable-array-setitem
|
||||
TKUnit.assert(array.getItem(1) === 5, "ObservableArray setItem() should set correct item!");
|
||||
@ -71,7 +70,7 @@ export const test_ObservableArray_setItemShouldRaiseCorrectEvent = function () {
|
||||
let addedCount: number;
|
||||
let removed: Array<number>;
|
||||
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
array.on("change", (args) => {
|
||||
index = args.index; // Index of the changed item.
|
||||
action = args.action; // Action. In this case Update.
|
||||
@ -81,14 +80,14 @@ export const test_ObservableArray_setItemShouldRaiseCorrectEvent = function () {
|
||||
array.setItem(1, 5);
|
||||
// << observable-array-eventdata
|
||||
TKUnit.assertEqual(index, 1);
|
||||
TKUnit.assertEqual(action, observableArrayModule.ChangeType.Update);
|
||||
TKUnit.assertEqual(action, ChangeType.Update);
|
||||
TKUnit.assertEqual(addedCount, 1);
|
||||
TKUnit.assertEqual(removed[0], 2);
|
||||
};
|
||||
|
||||
export const test_ObservableArray_concatShouldReturnNewArrayWithNewItemsAtTheEnd = function () {
|
||||
// >> observable-array-combine
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
const result = array.concat([4, 5, 6]);
|
||||
// << observable-array-combine
|
||||
TKUnit.assert(result.length === 6 && result[4] === 5, "ObservableArray concat() should add items at the end!");
|
||||
@ -96,7 +95,7 @@ export const test_ObservableArray_concatShouldReturnNewArrayWithNewItemsAtTheEnd
|
||||
|
||||
export const test_ObservableArray_joinShouldReturnStringWithAllItemsSeparatedWithComma = function () {
|
||||
// >> observable-array-join
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
const result = array.join();
|
||||
// << observable-array-join
|
||||
TKUnit.assert(result === "1,2,3", "ObservableArray join() should return string with all items separated with comma!");
|
||||
@ -104,7 +103,7 @@ export const test_ObservableArray_joinShouldReturnStringWithAllItemsSeparatedWit
|
||||
|
||||
export const test_ObservableArray_joinShouldReturnStringWithAllItemsSeparatedWithDot = function () {
|
||||
// >> observable-array-join-separator
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
const result = array.join(".");
|
||||
// << observable-array-join-separator
|
||||
TKUnit.assert(result === "1.2.3", "ObservableArray join() should return string with all items separated with dot!");
|
||||
@ -112,9 +111,9 @@ export const test_ObservableArray_joinShouldReturnStringWithAllItemsSeparatedWit
|
||||
|
||||
export const test_ObservableArray_popShouldRemoveTheLastElement = function () {
|
||||
// >> observable-array-join-pop
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
// >> (hide)
|
||||
const viewBase = new ViewBase();
|
||||
const viewBase = new Label();
|
||||
viewBase.set("testProperty", 0);
|
||||
viewBase.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
|
||||
// << (hide)
|
||||
@ -125,15 +124,15 @@ export const test_ObservableArray_popShouldRemoveTheLastElement = function () {
|
||||
};
|
||||
|
||||
export const test_ObservableArray_popShouldRemoveTheLastElementAndRaiseChangeEventWithCorrectArgs = function () {
|
||||
let result: observableArrayModule.ChangedData<number>;
|
||||
let result: ChangedData<number>;
|
||||
|
||||
// >> observable-array-join-change
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
// >> (hide)
|
||||
const index = array.length - 1;
|
||||
// << (hide)
|
||||
|
||||
array.on(observableArrayModule.ObservableArray.changeEvent, (args: observableArrayModule.ChangedData<number>) => {
|
||||
array.on(ObservableArray.changeEvent, (args: ChangedData<number>) => {
|
||||
// Argument (args) is ChangedData<T>.
|
||||
// args.eventName is "change".
|
||||
// args.action is "delete".
|
||||
@ -149,15 +148,15 @@ export const test_ObservableArray_popShouldRemoveTheLastElementAndRaiseChangeEve
|
||||
array.pop();
|
||||
// << observable-array-join-change
|
||||
|
||||
TKUnit.assert(result.eventName === observableArrayModule.ObservableArray.changeEvent && result.action === observableArrayModule.ChangeType.Delete &&
|
||||
TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Delete &&
|
||||
result.removed.length === 1 && result.index === index && result.addedCount === 0, "ObservableArray pop() should raise 'change' event with correct args!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_pushShouldAppendNewElement = function () {
|
||||
// >> observable-array-push
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
// >> (hide)
|
||||
const viewBase = new ViewBase();
|
||||
const viewBase = new Label();
|
||||
viewBase.set("testProperty", 0);
|
||||
viewBase.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
|
||||
// << (hide)
|
||||
@ -168,11 +167,11 @@ export const test_ObservableArray_pushShouldAppendNewElement = function () {
|
||||
};
|
||||
|
||||
export const test_ObservableArray_pushShouldAppendNewElementAndRaiseChangeEventWithCorrectArgs = function () {
|
||||
let result: observableArrayModule.ChangedData<number>;
|
||||
let result: ChangedData<number>;
|
||||
|
||||
// >> observable-array-change-push
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
array.on(observableArrayModule.ObservableArray.changeEvent, (args: observableArrayModule.ChangedData<number>) => {
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
array.on(ObservableArray.changeEvent, (args: ChangedData<number>) => {
|
||||
// Argument (args) is ChangedData<T>.
|
||||
// args.eventName is "change".
|
||||
// args.action is "add".
|
||||
@ -188,15 +187,15 @@ export const test_ObservableArray_pushShouldAppendNewElementAndRaiseChangeEventW
|
||||
array.push(4);
|
||||
// << observable-array-change-push
|
||||
|
||||
TKUnit.assert(result.eventName === observableArrayModule.ObservableArray.changeEvent && result.action === observableArrayModule.ChangeType.Add &&
|
||||
TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Add &&
|
||||
result.removed.length === 0 && result.index === 3 && result.addedCount === 1, "ObservableArray push() should raise 'change' event with correct args!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_pushShouldAppendNewElements = function () {
|
||||
// >> observable-array-push-multiple
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
// >> (hide)
|
||||
const viewBase = new ViewBase();
|
||||
const viewBase = new Label();
|
||||
viewBase.set("testProperty", 0);
|
||||
viewBase.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
|
||||
// << (hide)
|
||||
@ -207,11 +206,11 @@ export const test_ObservableArray_pushShouldAppendNewElements = function () {
|
||||
};
|
||||
|
||||
export const test_ObservableArray_pushShouldAppendNewElementsAndRaiseChangeEventWithCorrectArgs = function () {
|
||||
let result: observableArrayModule.ChangedData<number>;
|
||||
let result: ChangedData<number>;
|
||||
|
||||
// >> observable-array-push-multiple-info
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
array.on(observableArrayModule.ObservableArray.changeEvent, (args: observableArrayModule.ChangedData<number>) => {
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
array.on(ObservableArray.changeEvent, (args: ChangedData<number>) => {
|
||||
// Argument (args) is ChangedData<T>.
|
||||
// args.eventName is "change".
|
||||
// args.action is "add".
|
||||
@ -227,15 +226,15 @@ export const test_ObservableArray_pushShouldAppendNewElementsAndRaiseChangeEvent
|
||||
array.push(4, 5, 6);
|
||||
// << observable-array-push-multiple-info
|
||||
|
||||
TKUnit.assert(result.eventName === observableArrayModule.ObservableArray.changeEvent && result.action === observableArrayModule.ChangeType.Add &&
|
||||
TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Add &&
|
||||
result.removed.length === 0 && result.index === 3 && result.addedCount === 3, "ObservableArray push() should raise 'change' event with correct args!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_pushShouldAppendNewElementsFromSourceArray = function () {
|
||||
// >> observable-array-push-source
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
// >> (hide)
|
||||
const viewBase = new ViewBase();
|
||||
const viewBase = new Label();
|
||||
viewBase.set("testProperty", 0);
|
||||
viewBase.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
|
||||
// << (hide)
|
||||
@ -246,11 +245,11 @@ export const test_ObservableArray_pushShouldAppendNewElementsFromSourceArray = f
|
||||
};
|
||||
|
||||
export const test_ObservableArray_pushShouldAppendNewElementsFromSourceArrayAndRaiseChangeEventWithCorrectArgs = function () {
|
||||
let result: observableArrayModule.ChangedData<number>;
|
||||
let result: ChangedData<number>;
|
||||
|
||||
// >> observable-array-push-source-info
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
array.on(observableArrayModule.ObservableArray.changeEvent, (args: observableArrayModule.ChangedData<number>) => {
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
array.on(ObservableArray.changeEvent, (args: ChangedData<number>) => {
|
||||
// Argument (args) is ChangedData<T>.
|
||||
// args.eventName is "change".
|
||||
// args.action is "add".
|
||||
@ -266,13 +265,13 @@ export const test_ObservableArray_pushShouldAppendNewElementsFromSourceArrayAndR
|
||||
array.push([4, 5, 6]);
|
||||
// << observable-array-push-source-info
|
||||
|
||||
TKUnit.assert(result.eventName === observableArrayModule.ObservableArray.changeEvent && result.action === observableArrayModule.ChangeType.Add &&
|
||||
TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Add &&
|
||||
result.removed.length === 0 && result.index === 3 && result.addedCount === 3, "ObservableArray push() should raise 'change' event with correct args!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_reverseShouldReturnNewReversedArray = function () {
|
||||
// >> observable-array-reverse
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
const result = array.reverse();
|
||||
// << observable-array-reverse
|
||||
TKUnit.assert(result.length === 3 && result[0] === 3, "ObservableArray reverse() should return new reversed array!");
|
||||
@ -280,9 +279,9 @@ export const test_ObservableArray_reverseShouldReturnNewReversedArray = function
|
||||
|
||||
export const test_ObservableArray_shiftShouldRemoveTheFirstElement = function () {
|
||||
// >> observable-array-shift
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
// >> (hide)
|
||||
const viewBase = new ViewBase();
|
||||
const viewBase = new Label();
|
||||
viewBase.set("testProperty", 0);
|
||||
viewBase.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
|
||||
// << (hide)
|
||||
@ -293,12 +292,12 @@ export const test_ObservableArray_shiftShouldRemoveTheFirstElement = function ()
|
||||
};
|
||||
|
||||
export const test_ObservableArray_shiftShouldRemoveTheFirstElementAndRaiseChangeEventWithCorrectArgs = function () {
|
||||
let result: observableArrayModule.ChangedData<number>;
|
||||
let result: ChangedData<number>;
|
||||
|
||||
// >> observable-array-shift-change
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
|
||||
array.on(observableArrayModule.ObservableArray.changeEvent, (args: observableArrayModule.ChangedData<number>) => {
|
||||
array.on(ObservableArray.changeEvent, (args: ChangedData<number>) => {
|
||||
// Argument (args) is ChangedData<T>.
|
||||
// args.eventName is "change".
|
||||
// args.action is "delete".
|
||||
@ -314,13 +313,13 @@ export const test_ObservableArray_shiftShouldRemoveTheFirstElementAndRaiseChange
|
||||
array.shift();
|
||||
// << observable-array-shift-change
|
||||
|
||||
TKUnit.assert(result.eventName === observableArrayModule.ObservableArray.changeEvent && result.action === observableArrayModule.ChangeType.Delete &&
|
||||
TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Delete &&
|
||||
result.removed.length === 1 && result.index === 0 && result.addedCount === 0, "ObservableArray shift() should raise 'change' event with correct args!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_sliceShouldReturnSectionAsNewArray = function () {
|
||||
// >> observable-array-slice
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
const result = array.slice();
|
||||
// << observable-array-slice
|
||||
TKUnit.assert(result[2] === 3 && result.length === 3, "ObservableArray slice() should return section!");
|
||||
@ -328,7 +327,7 @@ export const test_ObservableArray_sliceShouldReturnSectionAsNewArray = function
|
||||
|
||||
export const test_ObservableArray_sliceWithParamsShouldReturnSectionAsNewArray = function () {
|
||||
// >> observable-array-slice-args
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3, 4, 5]);
|
||||
const array = new ObservableArray([1, 2, 3, 4, 5]);
|
||||
const result = array.slice(2, 4);
|
||||
// << observable-array-slice-args
|
||||
TKUnit.assert(result[1] === 4 && result.length === 2, "ObservableArray slice() should return section according to specified arguments!");
|
||||
@ -336,7 +335,7 @@ export const test_ObservableArray_sliceWithParamsShouldReturnSectionAsNewArray =
|
||||
|
||||
export const test_ObservableArray_sortShouldReturnNewSortedArray = function () {
|
||||
// >> observable-array-sort
|
||||
const array = new observableArrayModule.ObservableArray([3, 2, 1]);
|
||||
const array = new ObservableArray([3, 2, 1]);
|
||||
const result = array.sort();
|
||||
// << observable-array-sort
|
||||
TKUnit.assert(result[0] === 1 && result.length === 3, "ObservableArray sort() should return new sorted array!");
|
||||
@ -344,7 +343,7 @@ export const test_ObservableArray_sortShouldReturnNewSortedArray = function () {
|
||||
|
||||
export const test_ObservableArray_sortShouldReturnNewSortedArrayAccordingSpecifiedOrder = function () {
|
||||
// >> observable-array-sort-comparer
|
||||
const array = new observableArrayModule.ObservableArray([10, 100, 1]);
|
||||
const array = new ObservableArray([10, 100, 1]);
|
||||
const result = array.sort((a: number, b: number) => { return a - b; });
|
||||
// << observable-array-sort-comparer
|
||||
TKUnit.assert(result[2] === 100 && result.length === 3, "ObservableArray sort() should return new sorted array according to specified order!");
|
||||
@ -352,9 +351,9 @@ export const test_ObservableArray_sortShouldReturnNewSortedArrayAccordingSpecifi
|
||||
|
||||
export const test_ObservableArray_spliceShouldRemoveSpecifiedNumberOfElementsStartingFromSpecifiedIndex = function () {
|
||||
// >> observable-array-splice
|
||||
const array = new observableArrayModule.ObservableArray(["one", "two", "three"]);
|
||||
const array = new ObservableArray(["one", "two", "three"]);
|
||||
// >> (hide)
|
||||
const viewBase = new ViewBase();
|
||||
const viewBase = new Label();
|
||||
viewBase.set("testProperty", 0);
|
||||
viewBase.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
|
||||
// << (hide)
|
||||
@ -366,12 +365,12 @@ export const test_ObservableArray_spliceShouldRemoveSpecifiedNumberOfElementsSta
|
||||
};
|
||||
|
||||
export const test_ObservableArray_spliceShouldRemoveSpecifiedNumberOfElementsStartingFromSpecifiedIndexAndRaiseChangeEventWithCorrectArgs = function () {
|
||||
let result: observableArrayModule.ChangedData<number>;
|
||||
let result: ChangedData<number>;
|
||||
|
||||
// >> observable-array-splice-change
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
|
||||
array.on(observableArrayModule.ObservableArray.changeEvent, (args: observableArrayModule.ChangedData<number>) => {
|
||||
array.on(ObservableArray.changeEvent, (args: ChangedData<number>) => {
|
||||
// Argument (args) is ChangedData<T>.
|
||||
// args.eventName is "change".
|
||||
// args.action is "splice".
|
||||
@ -387,13 +386,13 @@ export const test_ObservableArray_spliceShouldRemoveSpecifiedNumberOfElementsSta
|
||||
array.splice(1, 2);
|
||||
// << observable-array-splice-change
|
||||
|
||||
TKUnit.assert(result.eventName === observableArrayModule.ObservableArray.changeEvent && result.action === observableArrayModule.ChangeType.Splice &&
|
||||
TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Splice &&
|
||||
result.removed.length === 2 && result.index === 1 && result.addedCount === 0, "ObservableArray splice() should raise 'change' event with correct args!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_spliceShouldInsertNewItemsInPlaceOfRemovedItemsStartingFromSpecifiedIndex = function () {
|
||||
// >> observable-array-splice-args
|
||||
const array = new observableArrayModule.ObservableArray(["one", "two", "three"]);
|
||||
const array = new ObservableArray(["one", "two", "three"]);
|
||||
const result = array.splice(1, 2, "six", "seven");
|
||||
// << observable-array-splice-args
|
||||
TKUnit.assert(result.length === 2 && result[0] === "two" && array.length === 3 && array.getItem(2) === "seven",
|
||||
@ -401,12 +400,12 @@ export const test_ObservableArray_spliceShouldInsertNewItemsInPlaceOfRemovedItem
|
||||
};
|
||||
|
||||
export const test_ObservableArray_spliceShouldRemoveAndInertSpecifiedNumberOfElementsStartingFromSpecifiedIndexAndRaiseChangeEventWithCorrectArgs = function () {
|
||||
let result: observableArrayModule.ChangedData<number>;
|
||||
let result: ChangedData<number>;
|
||||
|
||||
// >> observable-array-splice-args-change
|
||||
const array = new observableArrayModule.ObservableArray(["one", "two", "three"]);
|
||||
const array = new ObservableArray(["one", "two", "three"]);
|
||||
|
||||
array.on(observableArrayModule.ObservableArray.changeEvent, (args: observableArrayModule.ChangedData<number>) => {
|
||||
array.on(ObservableArray.changeEvent, (args: ChangedData<number>) => {
|
||||
// Argument (args) is ChangedData<T>.
|
||||
// args.eventName is "change".
|
||||
// args.action is "splice".
|
||||
@ -422,15 +421,15 @@ export const test_ObservableArray_spliceShouldRemoveAndInertSpecifiedNumberOfEle
|
||||
array.splice(1, 2, "six", "seven", "eight");
|
||||
// << observable-array-splice-args-change
|
||||
|
||||
TKUnit.assert(result.eventName === observableArrayModule.ObservableArray.changeEvent && result.action === observableArrayModule.ChangeType.Splice &&
|
||||
TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Splice &&
|
||||
result.removed.length === 2 && result.index === 1 && result.addedCount === 1, "ObservableArray splice() should raise 'change' event with correct args!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_unshiftShouldInsertNewElementsFromTheStart = function () {
|
||||
// >> observable-array-unshift
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
// >> (hide)
|
||||
const viewBase = new ViewBase();
|
||||
const viewBase = new Label();
|
||||
viewBase.set("testProperty", 0);
|
||||
viewBase.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
|
||||
// << (hide)
|
||||
@ -442,11 +441,11 @@ export const test_ObservableArray_unshiftShouldInsertNewElementsFromTheStart = f
|
||||
};
|
||||
|
||||
export const test_ObservableArray_unshiftShouldInsertNewElementsFromTheStartAndRaiseChangeEventWithCorrectArgs = function () {
|
||||
let result: observableArrayModule.ChangedData<number>;
|
||||
let result: ChangedData<number>;
|
||||
|
||||
// >> observable-array-unshift-change
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
array.on(observableArrayModule.ObservableArray.changeEvent, (args: observableArrayModule.ChangedData<number>) => {
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
array.on(ObservableArray.changeEvent, (args: ChangedData<number>) => {
|
||||
//// Argument (args) is ChangedData<T>.
|
||||
//// args.eventName is "change".
|
||||
//// args.action is "add".
|
||||
@ -462,13 +461,13 @@ export const test_ObservableArray_unshiftShouldInsertNewElementsFromTheStartAndR
|
||||
array.unshift(4, 5);
|
||||
// << observable-array-unshift-change
|
||||
|
||||
TKUnit.assert(result.eventName === observableArrayModule.ObservableArray.changeEvent && result.action === observableArrayModule.ChangeType.Add &&
|
||||
TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Add &&
|
||||
result.removed.length === 0 && result.index === 0 && result.addedCount === 2, "ObservableArray unshift() should raise 'change' event with correct args!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_indexOfShouldReturnCorrectIndex = function () {
|
||||
// >> observable-array-indexof
|
||||
const array = new observableArrayModule.ObservableArray(["one", "two", "three"]);
|
||||
const array = new ObservableArray(["one", "two", "three"]);
|
||||
const result = array.indexOf("two");
|
||||
// << observable-array-indexof
|
||||
TKUnit.assert(result === 1, "ObservableArray indexOf() should return correct index!");
|
||||
@ -476,14 +475,14 @@ export const test_ObservableArray_indexOfShouldReturnCorrectIndex = function ()
|
||||
|
||||
export const test_ObservableArray_indexOfShouldReturnCorrectIndexStartingFrom = function () {
|
||||
// >> observable-array-indexof-args
|
||||
const array = new observableArrayModule.ObservableArray(["one", "two", "three"]);
|
||||
const array = new ObservableArray(["one", "two", "three"]);
|
||||
const result = array.indexOf("two", 2);
|
||||
// << observable-array-indexof-args
|
||||
TKUnit.assert(result === -1, "ObservableArray indexOf() should return correct index!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_lastIndexOfShouldReturnCorrectIndex = function () {
|
||||
const array = new observableArrayModule.ObservableArray(["one", "two", "two", "three"]);
|
||||
const array = new ObservableArray(["one", "two", "two", "three"]);
|
||||
// >> observable-array-lastindexof
|
||||
const result = array.lastIndexOf("two");
|
||||
// << observable-array-lastindexof
|
||||
@ -492,21 +491,21 @@ export const test_ObservableArray_lastIndexOfShouldReturnCorrectIndex = function
|
||||
|
||||
export const test_ObservableArray_lastIndexOfShouldReturnCorrectIndexStartingFrom = function () {
|
||||
// >> observable-array-lastindexof-args
|
||||
const array = new observableArrayModule.ObservableArray(["one", "two", "two", "one", "three"]);
|
||||
const array = new ObservableArray(["one", "two", "two", "one", "three"]);
|
||||
const result = array.lastIndexOf("two", 1);
|
||||
// << observable-array-lastindexof-args
|
||||
TKUnit.assert(result === 1, "ObservableArray lastIndexOf() should return correct index!");
|
||||
};
|
||||
|
||||
export const test_ObservableArray_settingLengthToZeroPerformsSplice = function () {
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
|
||||
let changeRaised = false;
|
||||
array.on("change", (args: observableArrayModule.ChangedData<number>) => {
|
||||
array.on("change", (args: ChangedData<number>) => {
|
||||
changeRaised = true;
|
||||
TKUnit.assertEqual(args.object, array);
|
||||
TKUnit.assertEqual(args.eventName, "change");
|
||||
TKUnit.assertEqual(args.action, observableArrayModule.ChangeType.Splice);
|
||||
TKUnit.assertEqual(args.action, ChangeType.Splice);
|
||||
TKUnit.assertEqual(args.index, 0);
|
||||
TKUnit.assertEqual(args.addedCount, 0);
|
||||
TKUnit.arrayAssert(args.removed, [1, 2, 3]);
|
||||
@ -519,14 +518,14 @@ export const test_ObservableArray_settingLengthToZeroPerformsSplice = function (
|
||||
};
|
||||
|
||||
export const test_ObservableArray_settingLengthToSomethingPerformsSplice = function () {
|
||||
const array = new observableArrayModule.ObservableArray([1, 2, 3]);
|
||||
const array = new ObservableArray([1, 2, 3]);
|
||||
let changeRaised = false;
|
||||
|
||||
array.on("change", (args: observableArrayModule.ChangedData<number>) => {
|
||||
array.on("change", (args: ChangedData<number>) => {
|
||||
changeRaised = true;
|
||||
TKUnit.assertEqual(args.object, array);
|
||||
TKUnit.assertEqual(args.eventName, "change");
|
||||
TKUnit.assertEqual(args.action, observableArrayModule.ChangeType.Splice);
|
||||
TKUnit.assertEqual(args.action, ChangeType.Splice);
|
||||
TKUnit.assertEqual(args.index, 1);
|
||||
TKUnit.assertEqual(args.addedCount, 0);
|
||||
TKUnit.arrayAssert(args.removed, [2, 3]);
|
||||
@ -538,7 +537,7 @@ export const test_ObservableArray_settingLengthToSomethingPerformsSplice = funct
|
||||
TKUnit.assertTrue(changeRaised);
|
||||
};
|
||||
|
||||
const array = new observableArrayModule.ObservableArray();
|
||||
const array = new ObservableArray();
|
||||
|
||||
// We do not have indexer!
|
||||
export const test_getItem_isDefined = function () {
|
||||
@ -636,4 +635,4 @@ export const test_reduce_isDefined = function () {
|
||||
|
||||
export const test_reduceRight_isDefined = function () {
|
||||
TKUnit.assert(typeof (array.reduceRight) === "function", "Method 'reduceRight()' should be defined!");
|
||||
};
|
||||
};
|
@ -2,10 +2,8 @@
|
||||
import { Observable, fromObject, fromObjectRecursive, PropertyChangeData, EventData, WrappedValue } from "data/observable";
|
||||
// << observable-require
|
||||
|
||||
import * as dependencyObservable from "ui/core/dependency-observable";
|
||||
import * as TKUnit from "../TKUnit";
|
||||
import * as types from "utils/types";
|
||||
import * as proxy from "ui/core/proxy";
|
||||
import { ObservableArray } from "data/observable-array";
|
||||
|
||||
var TESTED_NAME = "tested";
|
||||
@ -87,45 +85,45 @@ export var test_Observable_UpdateAnotherPropertyWithinChangedCallback = function
|
||||
TKUnit.assert(obj.get("test") === "Changed test", "Changed value for property test is not correct!");
|
||||
}
|
||||
|
||||
export var test_DependencyObservable_UpdateAnotherPropertyWithinChangedCallback = function () {
|
||||
var obj = new dependencyObservable.DependencyObservable();
|
||||
// export var test_DependencyObservable_UpdateAnotherPropertyWithinChangedCallback = function () {
|
||||
// var obj = new dependencyObservable.DependencyObservable();
|
||||
|
||||
function onFirstPropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
||||
var testObj = <dependencyObservable.DependencyObservable>data.object;
|
||||
testObj._setValue(secondProperty, "Changed test");
|
||||
};
|
||||
// function onFirstPropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
||||
// var testObj = <dependencyObservable.DependencyObservable>data.object;
|
||||
// testObj._setValue(secondProperty, "Changed test");
|
||||
// };
|
||||
|
||||
var firstProperty = new dependencyObservable.Property(
|
||||
"first",
|
||||
"obj",
|
||||
new proxy.PropertyMetadata(
|
||||
"",
|
||||
dependencyObservable.PropertyMetadataSettings.None,
|
||||
onFirstPropertyChanged
|
||||
)
|
||||
);
|
||||
// var firstProperty = new dependencyObservable.Property(
|
||||
// "first",
|
||||
// "obj",
|
||||
// new proxy.PropertyMetadata(
|
||||
// "",
|
||||
// dependencyObservable.PropertyMetadataSettings.None,
|
||||
// onFirstPropertyChanged
|
||||
// )
|
||||
// );
|
||||
|
||||
var secondProperty = new dependencyObservable.Property(
|
||||
"second",
|
||||
"obj",
|
||||
new proxy.PropertyMetadata(
|
||||
"",
|
||||
dependencyObservable.PropertyMetadataSettings.None,
|
||||
null
|
||||
)
|
||||
);
|
||||
// var secondProperty = new dependencyObservable.Property(
|
||||
// "second",
|
||||
// "obj",
|
||||
// new proxy.PropertyMetadata(
|
||||
// "",
|
||||
// dependencyObservable.PropertyMetadataSettings.None,
|
||||
// null
|
||||
// )
|
||||
// );
|
||||
|
||||
obj._setValue(firstProperty, "Initial name");
|
||||
obj._setValue(secondProperty, "Initial test");
|
||||
// obj._setValue(firstProperty, "Initial name");
|
||||
// obj._setValue(secondProperty, "Initial test");
|
||||
|
||||
TKUnit.assert(obj._getValue(firstProperty) === "Initial name", "Initial value for property name is not correct!");
|
||||
TKUnit.assert(obj._getValue(secondProperty) === "Initial test", "Initial value for property test is not correct!");
|
||||
// TKUnit.assert(obj._getValue(firstProperty) === "Initial name", "Initial value for property name is not correct!");
|
||||
// TKUnit.assert(obj._getValue(secondProperty) === "Initial test", "Initial value for property test is not correct!");
|
||||
|
||||
obj._setValue(firstProperty, "Changed name");
|
||||
// obj._setValue(firstProperty, "Changed name");
|
||||
|
||||
TKUnit.assert(obj._getValue(firstProperty) === "Changed name", "Changed value for property name is not correct!");
|
||||
TKUnit.assert(obj._getValue(secondProperty) === "Changed test", "Changed value for property test is not correct!");
|
||||
}
|
||||
// TKUnit.assert(obj._getValue(firstProperty) === "Changed name", "Changed value for property name is not correct!");
|
||||
// TKUnit.assert(obj._getValue(secondProperty) === "Changed test", "Changed value for property test is not correct!");
|
||||
// }
|
||||
|
||||
export var test_Observable_addEventListener_SingleEvent = function () {
|
||||
var obj = new Observable();
|
||||
|
@ -43,7 +43,7 @@ allTests["OBSERVABLE"] = require("./data/observable-tests");
|
||||
allTests["TIMER"] = require("./timer-tests");
|
||||
allTests["COLOR"] = require("./color-tests");
|
||||
|
||||
allTests["DEPENDENCY-OBSERVABLE"] = require("./ui/dependency-observable-tests");
|
||||
// allTests["DEPENDENCY-OBSERVABLE"] = require("./ui/dependency-observable-tests");
|
||||
allTests["BINDABLE"] = require("./ui/bindable-tests");
|
||||
allTests["BINDING-EXPRESSIONS"] = require("./ui/binding-expressions-tests");
|
||||
allTests["XML-PARSER"] = require("./xml-parser-tests/xml-parser-tests");
|
||||
@ -196,6 +196,7 @@ function printRunTestStats() {
|
||||
btn.on("tap", () => runAll(testsSelector));
|
||||
stack.addChild(btn);
|
||||
let messageContainer = new TextView();
|
||||
messageContainer.editable = messageContainer.autocorrect = false;
|
||||
messageContainer.text = finalMessage;
|
||||
stack.addChild(messageContainer);
|
||||
topmost().currentPage.content = stack;
|
||||
|
@ -53,9 +53,7 @@ export function test_FormattedTextProperty_IsChanged_When_SpanIsChanged() {
|
||||
formattedTextChanged = true;
|
||||
});
|
||||
|
||||
firstSpan.beginEdit();
|
||||
firstSpan.fontSize = expectedValue;
|
||||
firstSpan.endEdit();
|
||||
|
||||
TKUnit.assertTrue(formattedTextChanged, "FormattedText property is not changed.");
|
||||
TKUnit.assert(formattedString.spans.getItem(0).fontSize === expectedValue, "FormattedString internal span is not changed as expected");
|
||||
@ -67,7 +65,7 @@ export function test_FormattedTextProperty_DoNotCrash_When_KnownColorIsSetForFor
|
||||
const expectedValue2 = "blue";
|
||||
|
||||
const firstSpan = new Span();
|
||||
firstSpan.foregroundColor = <any>expectedValue1;
|
||||
firstSpan.color = <any>expectedValue1;
|
||||
firstSpan.text = "LoremIpsum1";
|
||||
formattedString.spans.push(firstSpan);
|
||||
|
||||
@ -76,6 +74,6 @@ export function test_FormattedTextProperty_DoNotCrash_When_KnownColorIsSetForFor
|
||||
secondSpan.text = "LoremIpsum2";
|
||||
formattedString.spans.push(secondSpan);
|
||||
|
||||
TKUnit.assertEqual(formattedString.spans.getItem(0).foregroundColor.name, expectedValue1);
|
||||
TKUnit.assertEqual(formattedString.spans.getItem(0).color.name, expectedValue1);
|
||||
TKUnit.assertEqual(formattedString.spans.getItem(1).backgroundColor.name, expectedValue2);
|
||||
};
|
@ -9,7 +9,6 @@ import * as platform from "platform";
|
||||
import * as colorModule from "color";
|
||||
import * as formattedStringModule from "text/formatted-string";
|
||||
import * as spanModule from "text/span";
|
||||
import * as enums from "ui/enums";
|
||||
import { ActionBar } from "ui/action-bar";
|
||||
import { unsetValue } from "ui/core/view";
|
||||
|
||||
@ -212,22 +211,20 @@ export function _generateFormattedString(): formattedStringModule.FormattedStrin
|
||||
span = new spanModule.Span();
|
||||
span.fontFamily = "serif";
|
||||
span.fontSize = 10;
|
||||
span.fontAttributes = enums.FontAttributes.Bold;
|
||||
span.foregroundColor = new colorModule.Color("red");
|
||||
span.fontWeight = "bold";
|
||||
span.color = new colorModule.Color("red");
|
||||
span.backgroundColor = new colorModule.Color("blue");
|
||||
span.underline = 0;
|
||||
span.strikethrough = 1;
|
||||
span.textDecoration = "line-through";
|
||||
span.text = "Formatted";
|
||||
formattedString.spans.push(span);
|
||||
|
||||
span = new spanModule.Span();
|
||||
span.fontFamily = "sans-serif";
|
||||
span.fontSize = 20;
|
||||
span.fontAttributes = enums.FontAttributes.Italic;
|
||||
span.foregroundColor = new colorModule.Color("green");
|
||||
span.fontStyle = "italic";
|
||||
span.color = new colorModule.Color("green");
|
||||
span.backgroundColor = new colorModule.Color("yellow");
|
||||
span.underline = 1;
|
||||
span.strikethrough = 0;
|
||||
span.textDecoration = "underline";
|
||||
span.text = "Text";
|
||||
formattedString.spans.push(span);
|
||||
|
||||
|
@ -110,7 +110,7 @@ export class Observable implements ObservableDefinition {
|
||||
}
|
||||
|
||||
public notify<T extends EventData>(data: T) {
|
||||
const observers = this._getEventList(data.eventName);
|
||||
const observers = <Array<ListenerEntry>>this._observers[data.eventName];
|
||||
if (!observers) {
|
||||
return;
|
||||
}
|
||||
|
86
tns-core-modules/text/formatted-string.d.ts
vendored
86
tns-core-modules/text/formatted-string.d.ts
vendored
@ -3,100 +3,62 @@
|
||||
*/
|
||||
declare module "text/formatted-string" {
|
||||
import { Span } from "text/span";
|
||||
import { Observable } from "data/observable";
|
||||
import { ObservableArray } from "data/observable-array";
|
||||
import { View, AddArrayFromBuilder, AddChildFromBuilder } from "ui/core/view";
|
||||
import { ViewBase } from "ui/core/view";
|
||||
import { Color } from "color";
|
||||
import { FontStyle, FontWeight } from "ui/styling/font";
|
||||
import { TextDecoration } from "ui/text-base";
|
||||
|
||||
/**
|
||||
* Interface that specifies View that have formattedText property (like TextBase and Button).
|
||||
*/
|
||||
export interface FormattedStringView {
|
||||
formattedText: FormattedString;
|
||||
}
|
||||
|
||||
export { Span };
|
||||
|
||||
/**
|
||||
* A class used to create a formatted (rich text) string.
|
||||
*/
|
||||
class FormattedString extends Observable implements AddArrayFromBuilder, AddChildFromBuilder {
|
||||
export class FormattedString extends ViewBase {
|
||||
|
||||
/**
|
||||
* An observable collection of Span objects used to define common text properties.
|
||||
*/
|
||||
public spans: ObservableArray<Span>;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of FormattedString class.
|
||||
*/
|
||||
constructor();
|
||||
|
||||
/**
|
||||
* A human readable representation of the formatted string.
|
||||
*/
|
||||
public toString(): string;
|
||||
|
||||
/**
|
||||
* Gets or sets the font family which will be used for all spans that not have a specific value for font family.
|
||||
* Gets or sets the font family which will be used for all spans that doesn't have a specific value.
|
||||
*/
|
||||
public fontFamily: string;
|
||||
|
||||
/**
|
||||
* Gets or sets the font size which will be used for all spans that not have a specific value for font size.
|
||||
* Gets or sets the font size which will be used for all spans that doesn't have a specific value.
|
||||
*/
|
||||
public fontSize: number;
|
||||
|
||||
/**
|
||||
* Gets or sets the font attributes which will be used for all spans that not have a specific value for font attributes.
|
||||
* Gets or sets the font style which will be used for all spans that doesn't have a specific value.
|
||||
*/
|
||||
public fontAttributes: number;
|
||||
public fontStyle: FontStyle;
|
||||
|
||||
/**
|
||||
* Gets or sets the font foreground color which will be used for all spans that not have a specific value for font foreground color.
|
||||
* Gets or sets the font weight which will be used for all spans that doesn't have a specific value.
|
||||
*/
|
||||
public foregroundColor: Color;
|
||||
public fontWeight: FontWeight;
|
||||
|
||||
/**
|
||||
* Gets or sets the font background color which will be used for all spans that not have a specific value for font background color.
|
||||
* Gets or sets text decorations which will be used for all spans that doesn't have a specific value.
|
||||
*/
|
||||
public textDecoration: TextDecoration;
|
||||
|
||||
/**
|
||||
* Gets or sets the font foreground color which will be used for all spans that doesn't have a specific value.
|
||||
*/
|
||||
public color: Color;
|
||||
|
||||
/**
|
||||
* Gets or sets the font background color which will be used for all spans that doesn't have a specific value.
|
||||
*/
|
||||
public backgroundColor: Color;
|
||||
|
||||
/**
|
||||
* Gets or sets underline which will be used for all spans that not have a specific value for underline.
|
||||
*/
|
||||
public underline: number;
|
||||
|
||||
/**
|
||||
* Gets or sets strikethrough which will be used for all spans that not have a specific value for strikethrough.
|
||||
*/
|
||||
public strikethrough: number;
|
||||
|
||||
/**
|
||||
* Propogates binding context through the spans collection.
|
||||
* @param newBindingContext The value of the newly set binding context.
|
||||
*/
|
||||
public updateSpansBindingContext(newBindingContext: any): void
|
||||
|
||||
/**
|
||||
* Gets the parent view of the formatted string.
|
||||
*/
|
||||
public parent: View;
|
||||
|
||||
/**
|
||||
* A function that is called when an array declaration is found in xml.
|
||||
* @param name - Name of the array.
|
||||
* @param value - The actual value of the array.
|
||||
*/
|
||||
public _addArrayFromBuilder(name: string, value: Array<any>): void;
|
||||
|
||||
/**
|
||||
* Called for every child element declared in xml.
|
||||
* @param name - Name of the element.
|
||||
* @param value - Value of the element.
|
||||
*/
|
||||
public _addChildFromBuilder(name: string, value: any): void;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -1,145 +1,78 @@
|
||||
import { FormattedString as FormattedStringDefinition, FormattedStringView } from "text/formatted-string";
|
||||
import { FormattedString as FormattedStringDefinition } from "text/formatted-string";
|
||||
import { Span } from "text/span";
|
||||
import { Observable, PropertyChangeData } from "data/observable";
|
||||
import { ObservableArray, ChangedData } from "data/observable-array";
|
||||
import { View, AddArrayFromBuilder, AddChildFromBuilder } from "ui/core/view";
|
||||
import { isString } from "utils/types";
|
||||
import { ViewBase, AddArrayFromBuilder, AddChildFromBuilder } from "ui/core/view";
|
||||
import { Color } from "color";
|
||||
import { FontStyle, FontWeight } from "ui/styling/font";
|
||||
import { TextDecoration } from "ui/text-base";
|
||||
|
||||
export { Span };
|
||||
|
||||
export module knownCollections {
|
||||
export const spans = "spans";
|
||||
}
|
||||
|
||||
const CHILD_SPAN = "Span";
|
||||
const CHILD_FORMATTED_TEXT = "formattedText";
|
||||
const CHILD_FORMATTED_STRING = "FormattedString";
|
||||
|
||||
export class FormattedString extends Observable implements FormattedStringDefinition, AddArrayFromBuilder, AddChildFromBuilder {
|
||||
export class FormattedString extends ViewBase implements FormattedStringDefinition, AddArrayFromBuilder, AddChildFromBuilder {
|
||||
private _spans: ObservableArray<Span>;
|
||||
private _fontFamily: string;
|
||||
private _fontSize: number;
|
||||
private _foregroundColor: Color;
|
||||
private _backgroundColor: Color;
|
||||
private _underline: number;
|
||||
private _strikethrough: number;
|
||||
private _fontAttributes: number;
|
||||
private _parent: View;
|
||||
private _dummyPropertyChangedData: PropertyChangeData;
|
||||
|
||||
public _formattedText: any;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._spans = new ObservableArray<Span>();
|
||||
this._spans.addEventListener(ObservableArray.changeEvent, this.onSpansCollectionChanged, this);
|
||||
this._dummyPropertyChangedData = this._createPropertyChangeData("", this);
|
||||
}
|
||||
|
||||
get parent(): View {
|
||||
return this._parent;
|
||||
}
|
||||
set parent(value: View) {
|
||||
if (this._parent !== value) {
|
||||
this._parent = value;
|
||||
}
|
||||
}
|
||||
|
||||
get fontFamily(): string {
|
||||
return this._fontFamily;
|
||||
return this.style.fontFamily;
|
||||
}
|
||||
set fontFamily(value: string) {
|
||||
if (this._fontFamily !== value) {
|
||||
this._fontFamily = value;
|
||||
}
|
||||
this.style.fontFamily = value;
|
||||
}
|
||||
|
||||
get fontSize(): number {
|
||||
return this._fontSize;
|
||||
return this.style.fontSize;
|
||||
}
|
||||
set fontSize(value: number) {
|
||||
let fSize: number;
|
||||
if (isString(value)) {
|
||||
fSize = parseInt(<any>value);
|
||||
}
|
||||
else {
|
||||
fSize = value;
|
||||
}
|
||||
if (this._fontSize !== fSize) {
|
||||
this._fontSize = fSize;
|
||||
}
|
||||
this.style.fontSize = value;
|
||||
}
|
||||
|
||||
get foregroundColor(): Color {
|
||||
return this._foregroundColor;
|
||||
// Italic
|
||||
get fontStyle(): FontStyle {
|
||||
return this.style.fontStyle;
|
||||
}
|
||||
set foregroundColor(value: Color) {
|
||||
let foreColor;
|
||||
if (isString(value)) {
|
||||
foreColor = new Color(<any>value);
|
||||
}
|
||||
else {
|
||||
foreColor = value;
|
||||
}
|
||||
if (this._foregroundColor !== foreColor) {
|
||||
this._foregroundColor = foreColor;
|
||||
}
|
||||
set fontStyle(value: FontStyle) {
|
||||
this.style.fontStyle = value;
|
||||
}
|
||||
|
||||
// Bold
|
||||
get fontWeight(): FontWeight {
|
||||
return this.style.fontWeight;
|
||||
}
|
||||
set fontWeight(value: FontWeight) {
|
||||
this.style.fontWeight = value;
|
||||
}
|
||||
|
||||
get textDecoration(): TextDecoration {
|
||||
return this.style.textDecoration;
|
||||
}
|
||||
set textDecoration(value: TextDecoration) {
|
||||
this.style.textDecoration = value;
|
||||
}
|
||||
|
||||
get color(): Color {
|
||||
return this.style.color;
|
||||
}
|
||||
set color(value: Color) {
|
||||
this.style.color = value;
|
||||
}
|
||||
|
||||
get backgroundColor(): Color {
|
||||
return this._backgroundColor;
|
||||
return this.style.backgroundColor;
|
||||
}
|
||||
set backgroundColor(value: Color) {
|
||||
let backColor;
|
||||
if (isString(value)) {
|
||||
backColor = new Color(<any>value);
|
||||
}
|
||||
else {
|
||||
backColor = value;
|
||||
}
|
||||
if (this._backgroundColor !== backColor) {
|
||||
this._backgroundColor = backColor;
|
||||
}
|
||||
}
|
||||
|
||||
get underline(): number {
|
||||
return this._underline;
|
||||
}
|
||||
set underline(value: number) {
|
||||
let underlineIntValue: number;
|
||||
if (isString(value)) {
|
||||
underlineIntValue = parseInt(<any>value);
|
||||
}
|
||||
else {
|
||||
underlineIntValue = value;
|
||||
}
|
||||
if (this._underline !== underlineIntValue) {
|
||||
this._underline = underlineIntValue;
|
||||
}
|
||||
}
|
||||
|
||||
get strikethrough(): number {
|
||||
return this._strikethrough;
|
||||
}
|
||||
set strikethrough(value: number) {
|
||||
let strikethroughIntValue: number;
|
||||
if (isString(value)) {
|
||||
strikethroughIntValue = parseInt(<any>value);
|
||||
}
|
||||
else {
|
||||
strikethroughIntValue = value;
|
||||
}
|
||||
if (this._strikethrough !== strikethroughIntValue) {
|
||||
this._strikethrough = strikethroughIntValue;
|
||||
}
|
||||
}
|
||||
|
||||
get fontAttributes(): number {
|
||||
return this._fontAttributes;
|
||||
}
|
||||
set fontAttributes(value: number) {
|
||||
if (this._fontAttributes !== value) {
|
||||
this._fontAttributes = value;
|
||||
}
|
||||
this.style.backgroundColor = value;
|
||||
}
|
||||
|
||||
get spans(): ObservableArray<Span> {
|
||||
@ -158,13 +91,8 @@ export class FormattedString extends Observable implements FormattedStringDefini
|
||||
}
|
||||
|
||||
public _addArrayFromBuilder(name: string, value: Array<any>) {
|
||||
let i;
|
||||
let span;
|
||||
if (name === knownCollections.spans) {
|
||||
for (i = 0; i < value.length; i++) {
|
||||
span = value[i];
|
||||
this.spans.push(span);
|
||||
}
|
||||
this.spans.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,44 +102,61 @@ export class FormattedString extends Observable implements FormattedStringDefini
|
||||
}
|
||||
}
|
||||
|
||||
public updateSpansBindingContext(newBindingContext) {
|
||||
for (let i = 0, length = this.spans.length; i < length; i++) {
|
||||
let span = this.spans.getItem(i);
|
||||
span.bindingContext = newBindingContext;
|
||||
}
|
||||
}
|
||||
|
||||
public static addFormattedStringToView(view: FormattedStringView, name: string, value: any): void {
|
||||
if (name === CHILD_SPAN) {
|
||||
// NOTE: getter should either initialize the value or do it in the constructor.
|
||||
// if (!view.formattedText) {
|
||||
// view.formattedText = new FormattedString();
|
||||
// }
|
||||
view.formattedText.spans.push(value);
|
||||
}
|
||||
else if (name === CHILD_FORMATTED_TEXT || name === CHILD_FORMATTED_STRING) {
|
||||
view.formattedText = value;
|
||||
}
|
||||
}
|
||||
|
||||
private onSpansCollectionChanged(eventData: ChangedData<Span>) {
|
||||
if (eventData.addedCount > 0) {
|
||||
for (let i = 0; i < eventData.addedCount; i++) {
|
||||
let addedSpan: Span = (<ObservableArray<Span>>eventData.object).getItem(eventData.index + i);
|
||||
addedSpan.parentFormattedString = this;
|
||||
addedSpan.addEventListener(Observable.propertyChangeEvent, this.onSpanChanged, this);
|
||||
const span = (<ObservableArray<Span>>eventData.object).getItem(eventData.index + i);
|
||||
|
||||
// First add to logical tree so that inherited properties are set.
|
||||
this._addView(span);
|
||||
|
||||
// Then attach handlers - we skip the first nofitication because
|
||||
// we raise change for the whole instance.
|
||||
this.addPropertyChangeHandler(span);
|
||||
}
|
||||
}
|
||||
|
||||
if (eventData.removed && eventData.removed.length > 0) {
|
||||
for (let p = 0; p < eventData.removed.length; p++) {
|
||||
let removedSpan = eventData.removed[p];
|
||||
removedSpan.removeEventListener(Observable.propertyChangeEvent, this.onSpanChanged, this);
|
||||
const span = eventData.removed[p];
|
||||
|
||||
// First remove handlers so that we don't listen for changes
|
||||
// on inherited properties.
|
||||
this.removePropertyChangeHandler(span);
|
||||
|
||||
// Then remove the element.
|
||||
this._removeView(span);
|
||||
}
|
||||
}
|
||||
this.notify(this._dummyPropertyChangedData);
|
||||
|
||||
this.notifyPropertyChange('.', this);
|
||||
}
|
||||
|
||||
private onSpanChanged(eventData: PropertyChangeData) {
|
||||
this.notify(this._dummyPropertyChangedData);
|
||||
private addPropertyChangeHandler(span: Span) {
|
||||
const style = span.style;
|
||||
span.on(Observable.propertyChangeEvent, this.onPropertyChange, this);
|
||||
style.on("fontFamilyChange", this.onPropertyChange, this);
|
||||
style.on("fontSizeChange", this.onPropertyChange, this);
|
||||
style.on("fontStyleChange", this.onPropertyChange, this);
|
||||
style.on("fontWeightChange", this.onPropertyChange, this);
|
||||
style.on("textDecorationChange", this.onPropertyChange, this);
|
||||
style.on("colorChange", this.onPropertyChange, this);
|
||||
style.on("backgroundColorChange", this.onPropertyChange, this);
|
||||
}
|
||||
|
||||
private removePropertyChangeHandler(span: Span) {
|
||||
const style = span.style;
|
||||
span.off(Observable.propertyChangeEvent, this.onPropertyChange, this);
|
||||
style.off("fontFamilyChange", this.onPropertyChange, this);
|
||||
style.off("fontSizeChange", this.onPropertyChange, this);
|
||||
style.off("fontStyleChange", this.onPropertyChange, this);
|
||||
style.off("fontWeightChange", this.onPropertyChange, this);
|
||||
style.off("textDecorationChange", this.onPropertyChange, this);
|
||||
style.off("colorChange", this.onPropertyChange, this);
|
||||
style.off("backgroundColorChange", this.onPropertyChange, this);
|
||||
}
|
||||
|
||||
private onPropertyChange(data: PropertyChangeData) {
|
||||
this.notifyPropertyChange(data.propertyName, this);
|
||||
}
|
||||
}
|
@ -1,220 +0,0 @@
|
||||
import * as colorModule from "color";
|
||||
import * as definition from "text/span";
|
||||
import * as bindable from "ui/core/bindable";
|
||||
import * as types from "utils/types";
|
||||
import * as view from "ui/core/view";
|
||||
import * as enums from "ui/enums";
|
||||
import * as formattedString from "text/formatted-string";
|
||||
|
||||
export class Span extends bindable.Bindable implements definition.Span, view.ApplyXmlAttributes {
|
||||
private _fontFamily: string;
|
||||
private _fontSize: number;
|
||||
private _foregroundColor: colorModule.Color;
|
||||
private _backgroundColor: colorModule.Color;
|
||||
private _text: string;
|
||||
private _underline: number;
|
||||
private _strikethrough: number;
|
||||
private _fontAttributes: number;
|
||||
private _spanModifiers: Array<any>;
|
||||
private _parentFormattedString: formattedString.FormattedString;
|
||||
private _isInEditMode: boolean;
|
||||
|
||||
get fontFamily(): string {
|
||||
return this._fontFamily;
|
||||
}
|
||||
|
||||
set fontFamily(value: string) {
|
||||
if (this._fontFamily !== value) {
|
||||
this._fontFamily = value;
|
||||
this.updateAndNotify();
|
||||
}
|
||||
}
|
||||
|
||||
get fontSize(): number {
|
||||
return this._fontSize;
|
||||
}
|
||||
set fontSize(value: number) {
|
||||
var fSize: number;
|
||||
if (types.isString(value)) {
|
||||
fSize = parseInt(<any>value);
|
||||
}
|
||||
else {
|
||||
fSize = value;
|
||||
}
|
||||
if (this._fontSize !== fSize) {
|
||||
this._fontSize = fSize;
|
||||
this.updateAndNotify();
|
||||
}
|
||||
}
|
||||
|
||||
private _getColorValue(value: any): colorModule.Color {
|
||||
var result;
|
||||
if (types.isString(value) && colorModule.Color.isValid(value)) {
|
||||
result = new colorModule.Color(value);
|
||||
}
|
||||
else {
|
||||
result = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
get foregroundColor(): colorModule.Color {
|
||||
return this._foregroundColor;
|
||||
}
|
||||
set foregroundColor(value: colorModule.Color) {
|
||||
var convertedColor = this._getColorValue(value);
|
||||
if (this._foregroundColor !== convertedColor) {
|
||||
this._foregroundColor = convertedColor;
|
||||
this.updateAndNotify();
|
||||
}
|
||||
}
|
||||
|
||||
get backgroundColor(): colorModule.Color {
|
||||
return this._backgroundColor;
|
||||
}
|
||||
set backgroundColor(value: colorModule.Color) {
|
||||
var convertedColor = this._getColorValue(value);
|
||||
if (this._backgroundColor !== convertedColor) {
|
||||
this._backgroundColor = convertedColor;
|
||||
this.updateAndNotify();
|
||||
}
|
||||
}
|
||||
|
||||
get underline(): number {
|
||||
return this._underline;
|
||||
}
|
||||
|
||||
set underline(value: number) {
|
||||
var underlineIntValue: number;
|
||||
if (types.isString(value)) {
|
||||
underlineIntValue = parseInt(<any>value);
|
||||
}
|
||||
else {
|
||||
underlineIntValue = value;
|
||||
}
|
||||
if (this._underline !== underlineIntValue) {
|
||||
this._underline = underlineIntValue;
|
||||
this.updateAndNotify();
|
||||
}
|
||||
}
|
||||
|
||||
get strikethrough(): number {
|
||||
return this._strikethrough;
|
||||
}
|
||||
|
||||
set strikethrough(value: number) {
|
||||
var strikethroughIntValue: number;
|
||||
if (types.isString(value)) {
|
||||
strikethroughIntValue = parseInt(<any>value);
|
||||
}
|
||||
else {
|
||||
strikethroughIntValue = value;
|
||||
}
|
||||
if (this._strikethrough !== strikethroughIntValue) {
|
||||
this._strikethrough = strikethroughIntValue;
|
||||
this.updateAndNotify();
|
||||
}
|
||||
}
|
||||
|
||||
get fontAttributes(): number {
|
||||
return this._fontAttributes;
|
||||
}
|
||||
|
||||
set fontAttributes(value: number) {
|
||||
if (this._fontAttributes !== value) {
|
||||
this._fontAttributes = value;
|
||||
this.updateAndNotify();
|
||||
}
|
||||
}
|
||||
|
||||
get spanModifiers(): Array<any> {
|
||||
if (!this._spanModifiers) {
|
||||
this._spanModifiers = new Array();
|
||||
}
|
||||
return this._spanModifiers;
|
||||
}
|
||||
|
||||
get text(): string {
|
||||
return this._text;
|
||||
}
|
||||
|
||||
set text(value: string) {
|
||||
if (this._text !== value) {
|
||||
this._setTextInternal(value);
|
||||
this.updateAndNotify();
|
||||
}
|
||||
}
|
||||
|
||||
_setTextInternal(value: string): void {
|
||||
this._text = value;
|
||||
}
|
||||
|
||||
get parentFormattedString(): formattedString.FormattedString {
|
||||
return this._parentFormattedString;
|
||||
}
|
||||
|
||||
set parentFormattedString(value: formattedString.FormattedString) {
|
||||
if (this._parentFormattedString !== value) {
|
||||
this._parentFormattedString = value;
|
||||
this.updateAndNotify();
|
||||
}
|
||||
}
|
||||
|
||||
public updateSpanModifiers(parent: formattedString.FormattedString) {
|
||||
// a virtual method overridden in platform specific implementations.
|
||||
if (this._isInEditMode) {
|
||||
throw new Error("Cannot update span modifiers during update!");
|
||||
}
|
||||
this._spanModifiers = new Array();
|
||||
}
|
||||
|
||||
public beginEdit(): void {
|
||||
this._isInEditMode = true;
|
||||
}
|
||||
|
||||
private updateAndNotify() {
|
||||
if (!this._isInEditMode) {
|
||||
this.updateSpanModifiers(this.parentFormattedString);
|
||||
this.notify(this._createPropertyChangeData(".", this));
|
||||
}
|
||||
}
|
||||
|
||||
public endEdit(): void {
|
||||
this._isInEditMode = false;
|
||||
this.updateAndNotify();
|
||||
}
|
||||
|
||||
public _applyXmlAttribute(attribute, value): boolean {
|
||||
if (attribute === "fontAttributes") {
|
||||
if (value.indexOf(",")) {
|
||||
var fontAttr = value.split(",");
|
||||
var fontAttrValue;
|
||||
var j;
|
||||
for (j = 0; j < fontAttr.length; j++) {
|
||||
fontAttrValue = Span.getFontAttributeFromString(fontAttr[j]);
|
||||
this.fontAttributes |= fontAttrValue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.fontAttributes |= value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static getFontAttributeFromString(fontAttr: string) {
|
||||
var fontAttrTrimmedAndLowerCase = fontAttr.trim().toLowerCase();
|
||||
if (fontAttrTrimmedAndLowerCase === "bold") {
|
||||
return enums.FontAttributes.Bold;
|
||||
}
|
||||
else if (fontAttrTrimmedAndLowerCase === "italic") {
|
||||
return enums.FontAttributes.Italic;
|
||||
}
|
||||
else {
|
||||
return enums.FontAttributes.Normal;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
import * as spanCommon from "./span-common";
|
||||
import * as enums from "ui/enums";
|
||||
import * as formattedString from "text/formatted-string";
|
||||
import * as utils from "utils/utils";
|
||||
import * as fontModule from "ui/styling/font";
|
||||
|
||||
global.moduleMerge(spanCommon, exports);
|
||||
|
||||
var CustomTypefaceSpanClass;
|
||||
function ensureCustomTypefaceSpanClass() {
|
||||
if (CustomTypefaceSpanClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
class CustomTypefaceSpan extends android.text.style.TypefaceSpan {
|
||||
private typeface: any;
|
||||
|
||||
constructor(family: string, typeface: any) {
|
||||
super(family);
|
||||
this.typeface = typeface;
|
||||
return global.__native(this);
|
||||
}
|
||||
|
||||
public updateDrawState(ds: any): void {
|
||||
CustomTypefaceSpan.applyCustomTypeFace(ds, this.typeface);
|
||||
}
|
||||
|
||||
public updateMeasureState(paint: any): void {
|
||||
CustomTypefaceSpan.applyCustomTypeFace(paint, this.typeface);
|
||||
}
|
||||
|
||||
private static applyCustomTypeFace(paint: any, tf: any) {
|
||||
let oldStyle;
|
||||
let old = paint.getTypeface();
|
||||
if (old === null) {
|
||||
oldStyle = 0;
|
||||
} else {
|
||||
oldStyle = old.getStyle();
|
||||
}
|
||||
|
||||
let fake = oldStyle & ~tf.getStyle();
|
||||
if ((fake & android.graphics.Typeface.BOLD) !== 0) {
|
||||
paint.setFakeBoldText(true);
|
||||
}
|
||||
|
||||
if ((fake & android.graphics.Typeface.ITALIC) !== 0) {
|
||||
paint.setTextSkewX(-0.25);
|
||||
}
|
||||
|
||||
paint.setTypeface(tf);
|
||||
}
|
||||
}
|
||||
|
||||
CustomTypefaceSpanClass = CustomTypefaceSpan;
|
||||
}
|
||||
|
||||
export class Span extends spanCommon.Span {
|
||||
public updateSpanModifiers(parent: formattedString.FormattedString) {
|
||||
super.updateSpanModifiers(parent);
|
||||
var realFontFamily = this.fontFamily || (parent ? parent.fontFamily : undefined);
|
||||
if (realFontFamily) {
|
||||
let font = new fontModule.Font(realFontFamily,
|
||||
0,
|
||||
(realFontAttributes & enums.FontAttributes.Italic) ? enums.FontStyle.italic : enums.FontStyle.normal,
|
||||
(realFontAttributes & enums.FontAttributes.Bold) ? enums.FontWeight.bold : enums.FontWeight.normal);
|
||||
ensureCustomTypefaceSpanClass();
|
||||
let typefaceSpan: android.text.style.TypefaceSpan = new CustomTypefaceSpanClass(realFontFamily, font.getAndroidTypeface());
|
||||
this.spanModifiers.push(typefaceSpan);
|
||||
}
|
||||
var realFontSize = this.fontSize ||
|
||||
(parent ? parent.fontSize : undefined) ||
|
||||
(parent && parent.parent ? parent.parent.style.fontSize : undefined);
|
||||
if (realFontSize) {
|
||||
this.spanModifiers.push(new android.text.style.AbsoluteSizeSpan(realFontSize * utils.layout.getDisplayDensity()));
|
||||
}
|
||||
|
||||
var realForegroundColor = this.foregroundColor ||
|
||||
(parent ? parent.foregroundColor : undefined) ||
|
||||
(parent && parent.parent ? parent.parent.style.color : undefined);
|
||||
if (realForegroundColor) {
|
||||
this.spanModifiers.push(new android.text.style.ForegroundColorSpan(realForegroundColor.android));
|
||||
}
|
||||
|
||||
var realBackgroundColor = this.backgroundColor ||
|
||||
(parent ? parent.backgroundColor : undefined) ||
|
||||
(parent && parent.parent ? parent.parent.style.backgroundColor : undefined);
|
||||
if (realBackgroundColor) {
|
||||
this.spanModifiers.push(new android.text.style.BackgroundColorSpan(realBackgroundColor.android));
|
||||
}
|
||||
|
||||
var realFontAttributes = this.fontAttributes || (parent ? parent.fontAttributes : undefined);
|
||||
if (realFontAttributes) {
|
||||
if ((realFontAttributes & enums.FontAttributes.Bold) && (realFontAttributes & enums.FontAttributes.Italic)) {
|
||||
this.spanModifiers.push(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD_ITALIC));
|
||||
}
|
||||
else if (realFontAttributes & enums.FontAttributes.Bold) {
|
||||
this.spanModifiers.push(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD));
|
||||
}
|
||||
else if (realFontAttributes & enums.FontAttributes.Italic) {
|
||||
this.spanModifiers.push(new android.text.style.StyleSpan(android.graphics.Typeface.ITALIC));
|
||||
}
|
||||
}
|
||||
var realUnderline = this.underline || (parent ? parent.underline : undefined);
|
||||
if (realUnderline) {
|
||||
this.spanModifiers.push(new android.text.style.UnderlineSpan());
|
||||
}
|
||||
var realStrikethrough = this.strikethrough || (parent ? parent.strikethrough : undefined);
|
||||
if (realStrikethrough) {
|
||||
this.spanModifiers.push(new android.text.style.StrikethroughSpan());
|
||||
}
|
||||
}
|
||||
}
|
66
tns-core-modules/text/span.d.ts
vendored
66
tns-core-modules/text/span.d.ts
vendored
@ -1,12 +1,13 @@
|
||||
declare module "text/span" {
|
||||
import * as colorModule from "color";
|
||||
import * as bindable from "ui/core/bindable";
|
||||
import * as formattedString from "text/formatted-string";
|
||||
import { Color } from "color";
|
||||
import { ViewBase } from "ui/core/view-base";
|
||||
import { FontStyle, FontWeight } from "ui/styling/font";
|
||||
import { TextDecoration } from "ui/text-base";
|
||||
|
||||
/**
|
||||
* A class used to create a single part of formatted string with a common text properties.
|
||||
*/
|
||||
class Span extends bindable.Bindable {
|
||||
class Span extends ViewBase {
|
||||
/**
|
||||
* Gets or sets the font family of the span.
|
||||
*/
|
||||
@ -16,66 +17,39 @@
|
||||
* Gets or sets the font size of the span.
|
||||
*/
|
||||
public fontSize: number;
|
||||
|
||||
/**
|
||||
* Gets or sets the font style of the span.
|
||||
*/
|
||||
public fontStyle: FontStyle;
|
||||
|
||||
/**
|
||||
* Gets or sets the font attributes of the span.
|
||||
* It could be set to more than one value e.g. (Bold | Italic).
|
||||
* Gets or sets the font weight of the span.
|
||||
*/
|
||||
public fontAttributes: number;
|
||||
public fontWeight: FontWeight;
|
||||
|
||||
/**
|
||||
* Gets or sets text decorations for the span.
|
||||
*/
|
||||
public textDecoration: TextDecoration;
|
||||
|
||||
/**
|
||||
* Gets or sets the font foreground color of the span.
|
||||
*/
|
||||
public foregroundColor: colorModule.Color;
|
||||
public color: Color;
|
||||
|
||||
/**
|
||||
* Gets or sets the font background color of the span.
|
||||
*/
|
||||
public backgroundColor: colorModule.Color;
|
||||
|
||||
/**
|
||||
* Gets or sets underline for the span.
|
||||
*/
|
||||
public underline: number;
|
||||
|
||||
/**
|
||||
* Gets or sets strikethrough for the span.
|
||||
*/
|
||||
public strikethrough: number;
|
||||
|
||||
/**
|
||||
* A collection of modifiers build upon all text related properties.
|
||||
*/
|
||||
public spanModifiers: Array<any>;
|
||||
public backgroundColor: Color;
|
||||
|
||||
/**
|
||||
* Gets or sets the text for the span.
|
||||
*/
|
||||
public text: string;
|
||||
|
||||
/**
|
||||
* An instance of the parent formatted string (used internally to support some short hand property settings).
|
||||
*/
|
||||
public parentFormattedString: formattedString.FormattedString;
|
||||
|
||||
/**
|
||||
* Updates all span modifiers according to current values of all text related properties.
|
||||
*/
|
||||
public updateSpanModifiers(parent: formattedString.FormattedString): void;
|
||||
|
||||
/**
|
||||
* Initializes a process of updating a span (text related property(s)).
|
||||
*/
|
||||
public beginEdit(): void;
|
||||
|
||||
/**
|
||||
* Ends the process previously initiated by beginEdit and updates the span modifiers collection.
|
||||
*/
|
||||
public endEdit(): void;
|
||||
|
||||
|
||||
//@private
|
||||
_setTextInternal(value: string): void;
|
||||
//@endprivate
|
||||
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
import * as spanCommon from "./span-common";
|
||||
import * as enums from "ui/enums";
|
||||
import * as formattedString from "text/formatted-string";
|
||||
|
||||
import * as utils from "utils/utils";
|
||||
|
||||
global.moduleMerge(spanCommon, exports);
|
||||
|
||||
export class Span extends spanCommon.Span {
|
||||
public updateSpanModifiers(parent: formattedString.FormattedString) {
|
||||
super.updateSpanModifiers(parent);
|
||||
var realFontFamily = this.fontFamily || (parent ? parent.fontFamily : undefined);
|
||||
var realFontSize = this.fontSize ||
|
||||
(parent ? parent.fontSize : undefined) ||
|
||||
(parent && parent.parent ? parent.parent.style.fontSize : undefined);
|
||||
|
||||
var realFontAttributes = this.fontAttributes || (parent ? parent.fontAttributes : undefined);
|
||||
if (realFontAttributes || realFontFamily || realFontSize) {
|
||||
var font;
|
||||
if (!realFontSize) {
|
||||
realFontSize = utils.ios.getter(UIFont, UIFont.systemFontSize);
|
||||
}
|
||||
if (realFontFamily) {
|
||||
font = UIFont.fontWithNameSize(realFontFamily, realFontSize);
|
||||
}
|
||||
|
||||
if (!font) {
|
||||
var fontDescriptor = UIFontDescriptor.new();
|
||||
var symbolicTraits;
|
||||
if (realFontAttributes & enums.FontAttributes.Bold) {
|
||||
symbolicTraits |= UIFontDescriptorSymbolicTraits.TraitBold;
|
||||
}
|
||||
if (realFontAttributes & enums.FontAttributes.Italic) {
|
||||
symbolicTraits |= UIFontDescriptorSymbolicTraits.TraitItalic;
|
||||
}
|
||||
font = UIFont.fontWithDescriptorSize(fontDescriptor.fontDescriptorWithSymbolicTraits(symbolicTraits), realFontSize);
|
||||
}
|
||||
|
||||
this.spanModifiers.push({
|
||||
key: NSFontAttributeName,
|
||||
value: font
|
||||
});
|
||||
}
|
||||
|
||||
var realForegroundColor = this.foregroundColor ||
|
||||
(parent ? parent.foregroundColor : undefined) ||
|
||||
(parent && parent.parent ? parent.parent.style.color : undefined);
|
||||
if (realForegroundColor) {
|
||||
this.spanModifiers.push({
|
||||
key: NSForegroundColorAttributeName,
|
||||
value: realForegroundColor.ios
|
||||
});
|
||||
}
|
||||
|
||||
var realBackgroundColor = this.backgroundColor ||
|
||||
(parent ? parent.backgroundColor : undefined) ||
|
||||
(parent && parent.parent ? parent.parent.style.backgroundColor : undefined);
|
||||
if (realBackgroundColor) {
|
||||
this.spanModifiers.push({
|
||||
key: NSBackgroundColorAttributeName,
|
||||
value: realBackgroundColor.ios
|
||||
});
|
||||
}
|
||||
|
||||
var realUnderline = this.underline || (parent ? parent.underline : undefined);
|
||||
if (realUnderline) {
|
||||
this.spanModifiers.push({
|
||||
key: NSUnderlineStyleAttributeName,
|
||||
value: realUnderline
|
||||
});
|
||||
}
|
||||
var realStrikethrough = this.strikethrough || (parent ? parent.strikethrough : undefined);
|
||||
if (realStrikethrough) {
|
||||
this.spanModifiers.push({
|
||||
key: NSStrikethroughStyleAttributeName,
|
||||
value: realStrikethrough
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
74
tns-core-modules/text/span.ts
Normal file
74
tns-core-modules/text/span.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { Color } from "color";
|
||||
import { Span as SpanDefinition } from "text/span";
|
||||
import { ViewBase } from "ui/core/view";
|
||||
import { FontStyle, FontWeight, } from "ui/styling/font";
|
||||
import { TextDecoration } from "ui/text-base";
|
||||
|
||||
export class Span extends ViewBase implements SpanDefinition {
|
||||
private _text: string;
|
||||
|
||||
get fontFamily(): string {
|
||||
return this.style.fontFamily;
|
||||
}
|
||||
set fontFamily(value: string) {
|
||||
this.style.fontFamily = value;
|
||||
}
|
||||
|
||||
get fontSize(): number {
|
||||
return this.style.fontSize;
|
||||
}
|
||||
set fontSize(value: number) {
|
||||
this.style.fontSize = value;
|
||||
}
|
||||
|
||||
// Italic
|
||||
get fontStyle(): FontStyle {
|
||||
return this.style.fontStyle;
|
||||
}
|
||||
set fontStyle(value: FontStyle) {
|
||||
this.style.fontStyle = value;
|
||||
}
|
||||
|
||||
// Bold
|
||||
get fontWeight(): FontWeight {
|
||||
return this.style.fontWeight;
|
||||
}
|
||||
set fontWeight(value: FontWeight) {
|
||||
this.style.fontWeight = value;
|
||||
}
|
||||
|
||||
get textDecoration(): TextDecoration {
|
||||
return this.style.textDecoration;
|
||||
}
|
||||
set textDecoration(value: TextDecoration) {
|
||||
this.style.textDecoration = value;
|
||||
}
|
||||
|
||||
get color(): Color {
|
||||
return this.style.color;
|
||||
}
|
||||
set color(value: Color) {
|
||||
this.style.color = value;
|
||||
}
|
||||
|
||||
get backgroundColor(): Color {
|
||||
return this.style.backgroundColor;
|
||||
}
|
||||
set backgroundColor(value: Color) {
|
||||
this.style.backgroundColor = value;
|
||||
}
|
||||
|
||||
get text(): string {
|
||||
return this._text;
|
||||
}
|
||||
set text(value: string) {
|
||||
if (this._text !== value) {
|
||||
this._text = value;
|
||||
this.notifyPropertyChange("text", value);
|
||||
}
|
||||
}
|
||||
|
||||
_setTextInternal(value: string): void {
|
||||
this._text = value;
|
||||
}
|
||||
}
|
1
tns-core-modules/tns-core-modules.base.d.ts
vendored
1
tns-core-modules/tns-core-modules.base.d.ts
vendored
@ -45,7 +45,6 @@
|
||||
/// <reference path="ui/core/bindable.d.ts" />
|
||||
/// <reference path="ui/core/control-state-change.d.ts" />
|
||||
/// <reference path="ui/core/dependency-observable.d.ts" />
|
||||
/// <reference path="ui/core/proxy.d.ts" />
|
||||
/// <reference path="ui/core/view.d.ts" />
|
||||
/// <reference path="ui/core/weak-event-listener.d.ts" />
|
||||
/// <reference path="ui/date-picker/date-picker.d.ts" />
|
||||
|
32
tns-core-modules/ui/core/bindable.d.ts
vendored
32
tns-core-modules/ui/core/bindable.d.ts
vendored
@ -1,5 +1,4 @@
|
||||
declare module "ui/core/bindable" {
|
||||
import { DependencyObservable } from "ui/core/dependency-observable";
|
||||
import { ViewBase } from "ui/core/view-base";
|
||||
|
||||
/**
|
||||
@ -41,37 +40,6 @@
|
||||
toView: (...params: any[]) => any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an extended DependencyObservable object that supports data-binding.
|
||||
*/
|
||||
export class Bindable extends DependencyObservable {
|
||||
/**
|
||||
* Represents the dependency Property used to back the bindingContext value.
|
||||
*/
|
||||
// public static bindingContextProperty: dependencyObservable.Property;
|
||||
|
||||
/**
|
||||
* Gets or sets the binding context of this instance. This object is used as a source for each Binding that does not have a source object specified.
|
||||
*/
|
||||
bindingContext: any;
|
||||
/**
|
||||
* Establishes a binding between the source object and this Bindable instance.
|
||||
* @param options The options for the binding.
|
||||
* @param source An optional parameter, specifying the source object to bind to. If no source is specified the bindingContext value (if any) will be used as a source.
|
||||
*/
|
||||
bind(options: BindingOptions, source?: Object);
|
||||
/**
|
||||
* Removes the existing binding (if any) for the specified property.
|
||||
* @param property The name of the property to unbind.
|
||||
*/
|
||||
unbind(property: string);
|
||||
|
||||
//@private
|
||||
// _onBindingContextChanged(oldValue: any, newValue: any);
|
||||
// _updateTwoWayBinding(propertyName: string, value: any);
|
||||
//@endprivate
|
||||
}
|
||||
|
||||
export class Binding {
|
||||
constructor(target: ViewBase, options: BindingOptions);
|
||||
public bind(source: Object): void;
|
||||
|
@ -1,10 +1,9 @@
|
||||
import * as definition from "ui/core/bindable";
|
||||
import { BindingOptions } from "ui/core/bindable";
|
||||
import { Observable, PropertyChangeData } from "data/observable";
|
||||
import { unsetValue, DependencyObservable } from "ui/core/dependency-observable";
|
||||
import { addWeakEventListener, removeWeakEventListener } from "ui/core/weak-event-listener";
|
||||
import types = require("utils/types");
|
||||
import bindingBuilder = require("../builder/binding-builder");
|
||||
import { ViewBase, isEventOrGesture, bindingContextProperty } from "ui/core/view-base";
|
||||
import { ViewBase, isEventOrGesture, unsetValue } from "ui/core/view-base";
|
||||
import * as application from "application";
|
||||
import * as polymerExpressions from "js-libs/polymer-expressions";
|
||||
import * as utils from "utils/utils";
|
||||
@ -19,115 +18,6 @@ let paramsRegex = /\[\s*(['"])*(\w*)\1\s*\]/;
|
||||
|
||||
let bc = bindingBuilder.bindingConstants;
|
||||
|
||||
let defaultBindingSource = {};
|
||||
|
||||
export class Bindable extends DependencyObservable implements definition.Bindable {
|
||||
|
||||
public static bindingContextProperty = bindingContextProperty;
|
||||
|
||||
private bindings = new Map<string, Binding>();
|
||||
|
||||
get bindingContext(): Object {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
set bindingContext(value: Object) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public bind(options: definition.BindingOptions, source: Object = defaultBindingSource) {
|
||||
throw new Error("Not implemented");
|
||||
// let binding: Binding = this.bindings.get(options.targetProperty);
|
||||
// if (binding) {
|
||||
// binding.unbind();
|
||||
// }
|
||||
|
||||
// binding = new Binding(this, options);
|
||||
// this.bindings.set(options.targetProperty, binding);
|
||||
|
||||
// let bindingSource = source;
|
||||
// if (bindingSource === defaultBindingSource) {
|
||||
// bindingSource = this.bindingContext;
|
||||
// binding.sourceIsBindingContext = true;
|
||||
// }
|
||||
|
||||
// // if (!types.isNullOrUndefined(bindingSource)) {
|
||||
// binding.bind(bindingSource);
|
||||
// // }
|
||||
}
|
||||
|
||||
public unbind(property: string) {
|
||||
let binding: Binding = this.bindings.get(property);
|
||||
if (binding) {
|
||||
binding.unbind();
|
||||
this.bindings.delete(property);
|
||||
}
|
||||
}
|
||||
|
||||
// public _updateTwoWayBinding(propertyName: string, value: any) {
|
||||
// let binding: Binding = this.bindings.get(propertyName);
|
||||
// if (binding) {
|
||||
// binding.updateTwoWay(value);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public _setCore(data: PropertyChangeData) {
|
||||
// super._setCore(data);
|
||||
// this._updateTwoWayBinding(data.propertyName, data.value);
|
||||
// }
|
||||
|
||||
// public _onPropertyChanged(property: Property, oldValue: any, newValue: any) {
|
||||
// if (traceEnabled()) {
|
||||
// traceWrite(`${this}._onPropertyChanged(${property.name}, ${oldValue}, ${newValue})`, traceCategories.Binding);
|
||||
// }
|
||||
// super._onPropertyChanged(property, oldValue, newValue);
|
||||
// // if (this instanceof viewModule.View) {
|
||||
// // if (property.inheritable && (<viewModule.View>(<any>this))._isInheritedChange() === true) {
|
||||
// // return;
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// let binding = this.bindings.get(property.name);
|
||||
// if (binding && !binding.updating) {
|
||||
// if (binding.options.twoWay) {
|
||||
// if (traceEnabled()) {
|
||||
// traceWrite(`${this}._updateTwoWayBinding(${property.name}, ${newValue});` + property.name, traceCategories.Binding);
|
||||
// }
|
||||
// this._updateTwoWayBinding(property.name, newValue);
|
||||
// }
|
||||
// else {
|
||||
// if (traceEnabled()) {
|
||||
// traceWrite(`${this}.unbind(${property.name});`, traceCategories.Binding);
|
||||
// }
|
||||
// this.unbind(property.name);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// public _onBindingContextChanged(oldValue: any, newValue: any) {
|
||||
// let bindingContextBinding = this.bindings.get("bindingContext");
|
||||
// if (bindingContextBinding) {
|
||||
// if (!bindingContextBinding.updating) {
|
||||
// bindingContextBinding.bind(newValue);
|
||||
// }
|
||||
// }
|
||||
|
||||
// let bindingContextSource = this.bindingContext;
|
||||
|
||||
// this.bindings.forEach((binding, index, bindings) => {
|
||||
// if (!binding.updating && binding.sourceIsBindingContext && binding.options.targetProperty !== "bindingContext") {
|
||||
// if (traceEnabled()) {
|
||||
// traceWrite(`Binding ${binding.target.get()}.${binding.options.targetProperty} to new context ${bindingContextSource}`, traceCategories.Binding);
|
||||
// }
|
||||
// if (!types.isNullOrUndefined(bindingContextSource)) {
|
||||
// binding.bind(bindingContextSource);
|
||||
// } else {
|
||||
// binding.clearBinding();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
const emptyArray = [];
|
||||
function getProperties(property: string): Array<string> {
|
||||
let result: Array<string> = emptyArray;
|
||||
@ -166,9 +56,9 @@ export class Binding {
|
||||
|
||||
public updating: boolean;
|
||||
public sourceIsBindingContext: boolean;
|
||||
public options: definition.BindingOptions;
|
||||
public options: BindingOptions;
|
||||
|
||||
constructor(target: ViewBase, options: definition.BindingOptions) {
|
||||
constructor(target: ViewBase, options: BindingOptions) {
|
||||
this.target = new WeakRef(target);
|
||||
this.options = options;
|
||||
this.sourceProperties = getProperties(options.sourceProperty);
|
||||
@ -676,4 +566,4 @@ export class Binding {
|
||||
|
||||
this.updating = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,7 @@ declare module "ui/core/dependency-observable" {
|
||||
import { Observable, EventData } from "data/observable";
|
||||
|
||||
/**
|
||||
* Value specifing that Property value should be reset. Used when bindingContext on bound property is creared/null.
|
||||
*/
|
||||
export const unsetValue: any;
|
||||
|
||||
/**
|
||||
* Interface used by Propery 'defaultValueGetter' function to specify if the default value returned by the native instance can be cached or not.
|
||||
* One example is - android.widget.Button background. It is state drawable so it cannot be reused/cached.
|
||||
* @deprecated
|
||||
*/
|
||||
export interface NativeValueResult {
|
||||
result: any;
|
||||
@ -19,7 +13,7 @@ declare module "ui/core/dependency-observable" {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a special Property which supports changed callback, metadata and value validation.
|
||||
* @deprecated use 'ui/core/properties' module instead.
|
||||
*/
|
||||
export class Property {
|
||||
|
||||
@ -68,7 +62,7 @@ declare module "ui/core/dependency-observable" {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an Object that describes a Property instance.
|
||||
* @deprecated use 'ui/core/properties' module instead.
|
||||
*/
|
||||
export class PropertyMetadata {
|
||||
/**
|
||||
@ -121,7 +115,7 @@ declare module "ui/core/dependency-observable" {
|
||||
}
|
||||
|
||||
/**
|
||||
* The data for the event raised when a value of a Property changes for a DependencyObservable instance.
|
||||
* @deprecated use 'ui/core/properties' module instead.
|
||||
*/
|
||||
export interface PropertyChangeData extends EventData {
|
||||
/**
|
||||
@ -139,28 +133,28 @@ declare module "ui/core/dependency-observable" {
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the signature of the function that handles the propertyChanged event.
|
||||
* @deprecated use 'ui/core/properties' module instead.
|
||||
*/
|
||||
export interface PropertyChangedCallback {
|
||||
(data: PropertyChangeData): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the signature of the function that handles the validateValue event.
|
||||
* @deprecated use 'ui/core/properties' module instead.
|
||||
*/
|
||||
export interface PropertyValidationCallback {
|
||||
(value: any): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the signature of the function that compares if two property values are equal.
|
||||
* @deprecated use 'ui/core/properties' module instead.
|
||||
*/
|
||||
export interface PropertyEqualityComparer {
|
||||
(x: any, y: any): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an Object that is used to back a value for a Property in a DependencyObservable Object instance.
|
||||
* @deprecated
|
||||
*/
|
||||
export class PropertyEntry {
|
||||
/**
|
||||
@ -201,8 +195,7 @@ declare module "ui/core/dependency-observable" {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an extended Observable Object that uses Property instances for value backing mechanism.
|
||||
* This routine allows for various value modifiers per Property, which is used for inheritance, data-binding and styling purposes.
|
||||
* @deprecated use 'ui/core/view' as base class.
|
||||
*/
|
||||
export class DependencyObservable extends Observable {
|
||||
// TODO: Do we want to expose the get/setValue methods as public?
|
||||
@ -251,7 +244,7 @@ declare module "ui/core/dependency-observable" {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the possible values for the PropertyMetadata.options property. Each actual numeric value is a power of two allowing for bitwise operations.
|
||||
* @deprecated use 'ui/core/properties' module instead.
|
||||
*/
|
||||
export module PropertyMetadataSettings {
|
||||
/**
|
||||
@ -273,7 +266,7 @@ declare module "ui/core/dependency-observable" {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the possible values for the PropertyEntry.valueSource property.
|
||||
* @deprecated
|
||||
*/
|
||||
export module ValueSource {
|
||||
/**
|
||||
|
@ -6,10 +6,11 @@
|
||||
import { Observable, WrappedValue } from "data/observable";
|
||||
import { getClassInfo, isString } from "utils/types";
|
||||
|
||||
import { unsetValue } from "ui/core/properties";
|
||||
|
||||
// use private variables in the scope of the module rather than static members of the class since a member is still accessible through JavaScript and may be changed.
|
||||
var propertyFromKey = {};
|
||||
var propertyIdCounter = 0;
|
||||
export const unsetValue = new Object();
|
||||
// var propertyIdCounter = 0;
|
||||
|
||||
function generatePropertyKey(name: string, ownerType: string, validate?: boolean) {
|
||||
if (validate) {
|
||||
@ -72,16 +73,8 @@ export class PropertyMetadata implements PropertyMetadataDefinition {
|
||||
onChanged?: PropertyChangedCallback,
|
||||
onValidateValue?: PropertyValidationCallback,
|
||||
equalityComparer?: PropertyEqualityComparer) {
|
||||
|
||||
this.defaultValue = defaultValue;
|
||||
this.options = options;
|
||||
this.onValueChanged = onChanged;
|
||||
this.onValidateValue = onValidateValue;
|
||||
this.equalityComparer = equalityComparer;
|
||||
this.inheritable = (options & PropertyMetadataSettings.Inheritable) === PropertyMetadataSettings.Inheritable;
|
||||
this.affectsStyle = (options & PropertyMetadataSettings.AffectsStyle) === PropertyMetadataSettings.AffectsStyle;
|
||||
this.affectsLayout = (options & PropertyMetadataSettings.AffectsLayout) === PropertyMetadataSettings.AffectsLayout;
|
||||
}
|
||||
throw new Error("* @deprecated use 'ui/core/properties' module instead.");
|
||||
}
|
||||
}
|
||||
|
||||
export class Property implements PropertyDefinition {
|
||||
@ -101,33 +94,7 @@ export class Property implements PropertyDefinition {
|
||||
public valueConverter: (value: string) => any
|
||||
|
||||
constructor(public name: string, public ownerType: string, public metadata: PropertyMetadata, valueConverter?: (value: string) => any) {
|
||||
// register key
|
||||
this.key = generatePropertyKey(name, ownerType, true);
|
||||
if (propertyFromKey[this.key]) {
|
||||
throw new Error("Property " + name + " already registered for type " + ownerType + ".");
|
||||
}
|
||||
|
||||
propertyFromKey[this.key] = this;
|
||||
|
||||
if (!metadata || !(metadata instanceof PropertyMetadata)) {
|
||||
throw new Error("Expected valid PropertyMetadata instance.");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
this.nameEvent = name + "Change";
|
||||
this.ownerType = ownerType;
|
||||
this.metadata = metadata;
|
||||
|
||||
// generate a unique numeric id for each property (faster lookup than a string key)
|
||||
this.id = propertyIdCounter++;
|
||||
this.valueConverter = valueConverter;
|
||||
this.defaultValue = metadata.defaultValue;
|
||||
this.onValueChanged = metadata.onValueChanged;
|
||||
this.onValidateValue = metadata.onValidateValue;
|
||||
this.equalityComparer = metadata.equalityComparer || ((x, y) => x === y);
|
||||
this.inheritable = metadata.inheritable;
|
||||
this.affectsStyle = metadata.affectsStyle;
|
||||
this.affectsLayout = metadata.affectsLayout;
|
||||
throw new Error("* @deprecated use 'ui/core/properties' module instead.");
|
||||
}
|
||||
|
||||
public defaultValueGetter: (instance: DependencyObservable) => NativeValueResult;
|
||||
@ -143,6 +110,7 @@ export class PropertyEntry implements PropertyEntryDefinition {
|
||||
public visualStateValue: any;
|
||||
|
||||
constructor(public property: Property) {
|
||||
throw new Error("* @deprecated use 'ui/core/properties' module instead.");
|
||||
}
|
||||
|
||||
public resetValue() {
|
||||
@ -154,6 +122,10 @@ export class PropertyEntry implements PropertyEntryDefinition {
|
||||
export class DependencyObservable extends Observable implements DependencyObservableDefinition {
|
||||
private _propertyEntries = {};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
throw new Error("* @deprecated use 'ui/core/view-base or ui/core/view' as base class.");
|
||||
}
|
||||
public set(name: string, value: any) {
|
||||
var property = getPropertyByNameAndType(name, this);
|
||||
if (property) {
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { unsetValue } from "ui/core/dependency-observable";
|
||||
import { WrappedValue } from "data/observable";
|
||||
import { ViewBase } from "./view-base";
|
||||
import { Style } from "ui/styling/style";
|
||||
import * as definitions from "ui/core/view-base";
|
||||
|
||||
export { unsetValue, Style };
|
||||
export { Style };
|
||||
|
||||
export const unsetValue: any = new Object();
|
||||
|
||||
let symbolPropertyMap = {};
|
||||
let cssSymbolPropertyMap = {};
|
||||
@ -20,6 +21,7 @@ function print(map) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function printUnregisteredProperties(): void {
|
||||
print(symbolPropertyMap);
|
||||
print(cssSymbolPropertyMap)
|
||||
@ -34,7 +36,8 @@ const enum ValueSource {
|
||||
|
||||
export class Property<T extends ViewBase, U> implements PropertyDescriptor, definitions.Property<T, U> {
|
||||
private registered: boolean;
|
||||
private readonly name: string;
|
||||
|
||||
public readonly name: string;
|
||||
public readonly key: symbol;
|
||||
public readonly native: symbol;
|
||||
public readonly defaultValueKey: symbol;
|
||||
@ -90,12 +93,19 @@ export class Property<T extends ViewBase, U> implements PropertyDescriptor, defi
|
||||
const setNativeValue = this.nativeView && native in this;
|
||||
if (reset) {
|
||||
delete this[key];
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, unboxedValue);
|
||||
}
|
||||
if (setNativeValue) {
|
||||
this[native] = this[defaultValueKey];
|
||||
delete this[defaultValueKey];
|
||||
}
|
||||
} else {
|
||||
this[key] = unboxedValue;
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, unboxedValue);
|
||||
}
|
||||
|
||||
if (setNativeValue) {
|
||||
if (!(defaultValueKey in this)) {
|
||||
this[defaultValueKey] = this[native];
|
||||
@ -105,10 +115,6 @@ export class Property<T extends ViewBase, U> implements PropertyDescriptor, defi
|
||||
}
|
||||
}
|
||||
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, unboxedValue);
|
||||
}
|
||||
|
||||
if (this.hasListeners(eventName)) {
|
||||
this.notify({
|
||||
eventName: eventName,
|
||||
@ -237,12 +243,20 @@ export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescrip
|
||||
const setNativeValue = this.nativeView && native in this;
|
||||
if (reset) {
|
||||
delete this[key];
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, unboxedValue);
|
||||
}
|
||||
|
||||
if (setNativeValue) {
|
||||
this[native] = this[defaultValueKey];
|
||||
delete this[defaultValueKey];
|
||||
}
|
||||
} else {
|
||||
this[key] = unboxedValue;
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, unboxedValue);
|
||||
}
|
||||
|
||||
if (setNativeValue) {
|
||||
if (!(defaultValueKey in this)) {
|
||||
this[defaultValueKey] = this[native];
|
||||
@ -252,10 +266,6 @@ export class CoercibleProperty<T extends ViewBase, U> implements PropertyDescrip
|
||||
}
|
||||
}
|
||||
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, unboxedValue);
|
||||
}
|
||||
|
||||
if (this.hasListeners(eventName)) {
|
||||
this.notify({
|
||||
eventName: eventName,
|
||||
@ -337,7 +347,7 @@ export class InheritedProperty<T extends ViewBase, U> extends Property<T, U> imp
|
||||
const parent: ViewBase = that.parent;
|
||||
// If we have parent and it has non-default value we use as our inherited value.
|
||||
if (parent && parent[sourceKey] !== ValueSource.Default) {
|
||||
unboxedValue = parent[key];
|
||||
unboxedValue = parent[name];
|
||||
newValueSource = ValueSource.Inherited;
|
||||
}
|
||||
else {
|
||||
@ -448,12 +458,20 @@ export class CssProperty<T extends Style, U> implements definitions.CssProperty<
|
||||
const setNativeValue = view.nativeView && native in view;
|
||||
if (reset) {
|
||||
delete this[key];
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, value);
|
||||
}
|
||||
|
||||
if (setNativeValue) {
|
||||
view[native] = this[defaultValueKey];
|
||||
delete this[defaultValueKey];
|
||||
}
|
||||
} else {
|
||||
this[key] = value;
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, value);
|
||||
}
|
||||
|
||||
if (setNativeValue) {
|
||||
if (!(defaultValueKey in this)) {
|
||||
this[defaultValueKey] = view[native];
|
||||
@ -463,10 +481,6 @@ export class CssProperty<T extends Style, U> implements definitions.CssProperty<
|
||||
}
|
||||
}
|
||||
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, value);
|
||||
}
|
||||
|
||||
if (this.hasListeners(eventName)) {
|
||||
this.notify({
|
||||
eventName: eventName,
|
||||
@ -509,12 +523,20 @@ export class CssProperty<T extends Style, U> implements definitions.CssProperty<
|
||||
const setNativeValue = view.nativeView && native in view;
|
||||
if (reset) {
|
||||
delete this[key];
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, value);
|
||||
}
|
||||
|
||||
if (setNativeValue) {
|
||||
view[native] = this[defaultValueKey];
|
||||
delete this[defaultValueKey];
|
||||
}
|
||||
} else {
|
||||
this[key] = value;
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, value);
|
||||
}
|
||||
|
||||
if (setNativeValue) {
|
||||
if (!(defaultValueKey in this)) {
|
||||
this[defaultValueKey] = view[native];
|
||||
@ -524,10 +546,6 @@ export class CssProperty<T extends Style, U> implements definitions.CssProperty<
|
||||
}
|
||||
}
|
||||
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, value);
|
||||
}
|
||||
|
||||
if (this.hasListeners(eventName)) {
|
||||
this.notify({
|
||||
eventName: eventName,
|
||||
@ -574,7 +592,7 @@ export class CssProperty<T extends Style, U> implements definitions.CssProperty<
|
||||
}
|
||||
}
|
||||
|
||||
export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U> implements definitions.InheritedCssProperty<T,U> {
|
||||
export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U> implements definitions.InheritedCssProperty<T, U> {
|
||||
public setInheritedValue: (value: U) => void;
|
||||
|
||||
constructor(options: definitions.CssPropertyOptions<T, U>) {
|
||||
@ -614,8 +632,8 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
|
||||
let parent = view.parent;
|
||||
let style = parent ? parent.style : null
|
||||
// If we have parent and it has non-default value we use as our inherited value.
|
||||
if (style && style[sourceKey] !== ValueSource.Default) {
|
||||
newValue = style[key];
|
||||
if (style && style[sourceKey] > ValueSource.Default) {
|
||||
newValue = style[name];
|
||||
this[sourceKey] = ValueSource.Inherited;
|
||||
}
|
||||
else {
|
||||
@ -639,12 +657,20 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
|
||||
const setNativeValue = view.nativeView && native in view;
|
||||
if (reset) {
|
||||
delete this[key];
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, newValue);
|
||||
}
|
||||
|
||||
if (setNativeValue) {
|
||||
view[native] = this[defaultValueKey];
|
||||
delete this[defaultValueKey];
|
||||
}
|
||||
} else {
|
||||
this[key] = newValue;
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, newValue);
|
||||
}
|
||||
|
||||
if (setNativeValue) {
|
||||
if (!(defaultValueKey in this)) {
|
||||
this[defaultValueKey] = view[native];
|
||||
@ -654,10 +680,6 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
|
||||
}
|
||||
}
|
||||
|
||||
if (valueChanged) {
|
||||
valueChanged(this, currentValue, newValue);
|
||||
}
|
||||
|
||||
if (this.hasListeners(eventName)) {
|
||||
this.notify({
|
||||
eventName: eventName,
|
||||
@ -722,13 +744,9 @@ export class ShorthandProperty<T extends Style, P> implements definitions.Shorth
|
||||
const cssName = `css-${options.cssName}`;
|
||||
this.cssName = cssName;
|
||||
|
||||
const sourceKey = Symbol(name + ":valueSourceKey");
|
||||
this.sourceKey = sourceKey;
|
||||
|
||||
const converter = options.converter;
|
||||
|
||||
function setLocalValue(this: T, value: string | P): void {
|
||||
this[sourceKey] = ValueSource.Local;
|
||||
if (this[key] !== value) {
|
||||
this[key] = value;
|
||||
for (let [p, v] of converter(value)) {
|
||||
@ -738,12 +756,6 @@ export class ShorthandProperty<T extends Style, P> implements definitions.Shorth
|
||||
}
|
||||
|
||||
function setCssValue(this: T, value: string): void {
|
||||
const currentValueSource: number = this[sourceKey] || ValueSource.Default;
|
||||
// We have localValueSource - NOOP.
|
||||
if (currentValueSource === ValueSource.Local) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this[key] !== value) {
|
||||
this[key] = value;
|
||||
for (let [p, v] of converter(value)) {
|
||||
@ -785,7 +797,9 @@ function inheritablePropertyValuesOn(view: ViewBase): Array<{ property: Inherite
|
||||
const sourceKey = prop.sourceKey;
|
||||
const valueSource: number = view[sourceKey] || ValueSource.Default;
|
||||
if (valueSource !== ValueSource.Default) {
|
||||
array.push({ property: prop, value: view[prop.key] });
|
||||
// use prop.name as it will return value or default value.
|
||||
// prop.key will return undefined if property is set t the same value as default one.
|
||||
array.push({ property: prop, value: view[prop.name] });
|
||||
}
|
||||
}
|
||||
|
||||
@ -798,7 +812,9 @@ function inheritableCssPropertyValuesOn(style: Style): Array<{ property: Inherit
|
||||
const sourceKey = prop.sourceKey;
|
||||
const valueSource: number = style[sourceKey] || ValueSource.Default;
|
||||
if (valueSource !== ValueSource.Default) {
|
||||
array.push({ property: prop, value: style[prop.key] });
|
||||
// use prop.name as it will return value or default value.
|
||||
// prop.key will return undefined if property is set t the same value as default one.
|
||||
array.push({ property: prop, value: style[prop.name] });
|
||||
}
|
||||
}
|
||||
|
||||
@ -929,9 +945,10 @@ export function makeValidator<T>(...values: T[]): (value: any) => value is T {
|
||||
const set = new Set(values);
|
||||
return (value: any): value is T => set.has(value);
|
||||
}
|
||||
|
||||
export function makeParser<T>(isValid: (value: any) => boolean, def: T): (value: any) => T {
|
||||
return value => {
|
||||
const lower = value && value.toLowerCase();
|
||||
return isValid(lower) ? lower : def;
|
||||
}
|
||||
}
|
||||
}
|
65
tns-core-modules/ui/core/proxy.d.ts
vendored
65
tns-core-modules/ui/core/proxy.d.ts
vendored
@ -1,65 +0,0 @@
|
||||
declare module "ui/core/proxy" {
|
||||
import { DependencyObservable, Property, PropertyMetadata as PropertyMetadataBase, PropertyChangedCallback, PropertyValidationCallback } from "ui/core/dependency-observable";
|
||||
|
||||
/**
|
||||
* A class that describes dependency property metadata.
|
||||
*/
|
||||
class PropertyMetadata extends PropertyMetadataBase {
|
||||
/**
|
||||
* Gets or sets a dependencyObservable.PropertyChangedCallback which is used to set the value on native side.
|
||||
*/
|
||||
public onSetNativeValue: PropertyChangedCallback;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of PropertyMetadata class.
|
||||
* @param defaultValue A value to be used as default value for the dependency property.
|
||||
* @param options (optional) A value that states how this property affects visual tree.
|
||||
* @param onChanged (optional) A callback function which will be executed when value of the dependency property is changed.
|
||||
* @param onValidateValue (optional) A callback function which will be executed to validate the value of the dependency property.
|
||||
* @param onSetNativeValue (optional) A callback function which will be executed to set the value on native side.
|
||||
*/
|
||||
constructor(
|
||||
defaultValue: any,
|
||||
options?: number,
|
||||
onChanged?: PropertyChangedCallback,
|
||||
onValidateValue?: PropertyValidationCallback,
|
||||
onSetNativeValue?: PropertyChangedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that serves as a proxy between JavaScript object and native object.
|
||||
* Used in cases when native instance is not avaibale yet (stores all properties).
|
||||
*/
|
||||
class ProxyObject extends DependencyObservable {
|
||||
|
||||
/**
|
||||
* Get the nativeView created for this object.
|
||||
*/
|
||||
public nativeView: any;
|
||||
|
||||
/**
|
||||
* Gets the android-specific native instance that lies behind this proxy. Will be available if running on an Android platform.
|
||||
*/
|
||||
public android: any;
|
||||
|
||||
/**
|
||||
* Gets the ios-specific native instance that lies behind this proxy. Will be available if running on an iOS platform.
|
||||
*/
|
||||
public ios: any;
|
||||
|
||||
/**
|
||||
* A property is changed.
|
||||
*/
|
||||
// public _onPropertyChanged(property: dependencyObservable.Property, oldValue: any, newValue: any): void;
|
||||
|
||||
/**
|
||||
* A property has changed on the native side directly - e.g. the user types in a TextField.
|
||||
*/
|
||||
public _onPropertyChangedFromNative(property: Property, newValue: any): void;
|
||||
|
||||
/**
|
||||
* Synchronizes all properties with native values.
|
||||
*/
|
||||
// public _syncNativeProperties(): void;
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
import * as bindable from "ui/core/bindable";
|
||||
import * as dependencyObservable from "ui/core/dependency-observable";
|
||||
import * as definition from "ui/core/proxy";
|
||||
|
||||
export class PropertyMetadata extends dependencyObservable.PropertyMetadata implements definition.PropertyMetadata {
|
||||
private _onSetNativeValue: dependencyObservable.PropertyChangedCallback;
|
||||
|
||||
constructor(
|
||||
defaultValue: any,
|
||||
options?: number,
|
||||
onChanged?: dependencyObservable.PropertyChangedCallback,
|
||||
onValidateValue?: dependencyObservable.PropertyValidationCallback,
|
||||
onSetNativeValue?: dependencyObservable.PropertyChangedCallback) {
|
||||
super(defaultValue, options, onChanged, onValidateValue);
|
||||
this._onSetNativeValue = onSetNativeValue;
|
||||
}
|
||||
|
||||
get onSetNativeValue(): dependencyObservable.PropertyChangedCallback {
|
||||
return this._onSetNativeValue;
|
||||
}
|
||||
set onSetNativeValue(value: dependencyObservable.PropertyChangedCallback) {
|
||||
this._onSetNativeValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
export class ProxyObject extends bindable.Bindable implements definition.ProxyObject {
|
||||
private _updatingJSPropertiesDict = {};
|
||||
|
||||
public nativeView: any;
|
||||
|
||||
/**
|
||||
* Gets the android-specific native instance that lies behind this proxy. Will be available if running on an Android platform.
|
||||
*/
|
||||
get android(): any {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ios-specific native instance that lies behind this proxy. Will be available if running on an iOS platform.
|
||||
*/
|
||||
get ios(): any {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// public _onPropertyChanged(property: dependencyObservable.Property, oldValue: any, newValue: any) {
|
||||
// super._onPropertyChanged(property, oldValue, newValue);
|
||||
|
||||
// this._trySetNativeValue(property, oldValue, newValue);
|
||||
// }
|
||||
|
||||
/**
|
||||
* A property has changed on the native side directly - e.g. the user types in a TextField.
|
||||
*/
|
||||
public _onPropertyChangedFromNative(property: dependencyObservable.Property, newValue: any) {
|
||||
if (this._updatingJSPropertiesDict[property.name]) {
|
||||
return;
|
||||
}
|
||||
this._updatingJSPropertiesDict[property.name] = true;
|
||||
this._setValue(property, newValue);
|
||||
delete this._updatingJSPropertiesDict[property.name];
|
||||
}
|
||||
|
||||
// public _syncNativeProperties() {
|
||||
// // var that = this;
|
||||
// // var eachPropertyCallback = function (property: dependencyObservable.Property): boolean {
|
||||
// // that._trySetNativeValue(property);
|
||||
// // return true;
|
||||
// // }
|
||||
|
||||
// // this._eachSetProperty(eachPropertyCallback);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Checks whether the proxied native object has been created and properties may be applied to it.
|
||||
*/
|
||||
// protected _canApplyNativeProperty(): boolean {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// private _trySetNativeValue(property: dependencyObservable.Property, oldValue?: any, newValue?: any) {
|
||||
// if (this._updatingJSPropertiesDict[property.name]) {
|
||||
// // This is the case when a property has changed from the native side directly and we have received the "_onPropertyChanged" event while synchronizing our local cache
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (!this._canApplyNativeProperty()) {
|
||||
// // in android we have lazy loading and we do not have a native widget created yet, do not call the onSetNativeValue callback
|
||||
// // properties will be synced when the widget is created
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var metadata = property.metadata;
|
||||
// if (!(metadata instanceof PropertyMetadata)) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var proxyMetadata = <PropertyMetadata>metadata;
|
||||
// if (proxyMetadata.onSetNativeValue) {
|
||||
// if (types.isUndefined(newValue)) {
|
||||
// newValue = this._getValue(property);
|
||||
// }
|
||||
|
||||
// proxyMetadata.onSetNativeValue({
|
||||
// object: this,
|
||||
// property: property,
|
||||
// eventName: observable.Observable.propertyChangeEvent,
|
||||
// newValue: newValue,
|
||||
// oldValue: oldValue
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { ViewBase as ViewBaseDefinition } from "ui/core/view-base";
|
||||
import { Observable, EventData, PropertyChangeData } from "data/observable";
|
||||
import { Property, InheritedProperty, Style, clearInheritedProperties, propagateInheritedProperties, resetCSSProperties, applyNativeSetters, resetStyleProperties } from "./properties";
|
||||
import { Binding, BindingOptions, Bindable } from "ui/core/bindable";
|
||||
import { Binding, BindingOptions } from "ui/core/bindable";
|
||||
import { isIOS, isAndroid } from "platform";
|
||||
import { fromString as gestureFromString } from "ui/gestures";
|
||||
import { SelectorCore } from "ui/styling/css-selector";
|
||||
@ -21,7 +21,7 @@ function ensureStyleScopeModule() {
|
||||
}
|
||||
|
||||
export {
|
||||
Observable, EventData, Binding, BindingOptions, Bindable, isIOS, isAndroid,
|
||||
Observable, EventData, Binding, BindingOptions, isIOS, isAndroid,
|
||||
gestureFromString, traceEnabled, traceWrite, traceCategories, traceNotifyEvent, isCategorySet
|
||||
};
|
||||
export * from "./properties";
|
||||
|
@ -5,7 +5,7 @@ import { Background } from "ui/styling/background";
|
||||
import {
|
||||
ViewBase, getEventOrGestureName, EventData, Style, unsetValue,
|
||||
Property, CssProperty, ShorthandProperty, InheritedCssProperty,
|
||||
gestureFromString, isIOS, traceEnabled, traceWrite, traceCategories, printUnregisteredProperties, makeParser, makeValidator
|
||||
gestureFromString, isIOS, traceEnabled, traceWrite, traceCategories, makeParser, makeValidator
|
||||
} from "./view-base";
|
||||
import { observe as gestureObserve, GesturesObserver, GestureTypes, GestureEventData } from "ui/gestures";
|
||||
import { Font, parseFont, FontStyle, FontWeight } from "ui/styling/font";
|
||||
@ -28,7 +28,7 @@ export {
|
||||
import * as am from "ui/animation";
|
||||
let animationModule: typeof am;
|
||||
function ensureAnimationModule() {
|
||||
if (!animationModule){
|
||||
if (!animationModule) {
|
||||
animationModule = require("ui/animation");
|
||||
}
|
||||
}
|
||||
@ -1429,39 +1429,39 @@ function convertToTransform(value: string): [CssProperty<any, any>, any][] {
|
||||
for (let transform in newTransform) {
|
||||
switch (transform) {
|
||||
case "scaleX":
|
||||
array.push([scaleXProperty, parseFloat(newTransform[transform])]);
|
||||
array.push([scaleXProperty, newTransform[transform]]);
|
||||
break;
|
||||
case "scaleY":
|
||||
array.push([scaleYProperty, parseFloat(newTransform[transform])]);
|
||||
array.push([scaleYProperty, newTransform[transform]]);
|
||||
break;
|
||||
case "scale":
|
||||
case "scale3d":
|
||||
values = newTransform[transform].split(",");
|
||||
if (values.length >= 2) {
|
||||
array.push([scaleXProperty, parseFloat(values[0])]);
|
||||
array.push([scaleYProperty, parseFloat(values[1])]);
|
||||
array.push([scaleXProperty, values[0]]);
|
||||
array.push([scaleYProperty, values[1]]);
|
||||
}
|
||||
else if (values.length === 1) {
|
||||
array.push([scaleXProperty, parseFloat(values[0])]);
|
||||
array.push([scaleYProperty, parseFloat(values[0])]);
|
||||
array.push([scaleXProperty, values[0]]);
|
||||
array.push([scaleYProperty, values[0]]);
|
||||
}
|
||||
break;
|
||||
case "translateX":
|
||||
array.push([translateXProperty, parseFloat(newTransform[transform])]);
|
||||
array.push([translateXProperty, newTransform[transform]]);
|
||||
break;
|
||||
case "translateY":
|
||||
array.push([translateYProperty, parseFloat(newTransform[transform])]);
|
||||
array.push([translateYProperty, newTransform[transform]]);
|
||||
break;
|
||||
case "translate":
|
||||
case "translate3d":
|
||||
values = newTransform[transform].split(",");
|
||||
if (values.length >= 2) {
|
||||
array.push([translateXProperty, parseFloat(values[0])]);
|
||||
array.push([translateYProperty, parseFloat(values[1])]);
|
||||
array.push([translateXProperty, values[0]]);
|
||||
array.push([translateYProperty, values[1]]);
|
||||
}
|
||||
else if (values.length === 1) {
|
||||
array.push([translateXProperty, parseFloat(values[0])]);
|
||||
array.push([translateYProperty, parseFloat(values[0])]);
|
||||
array.push([translateXProperty, values[0]]);
|
||||
array.push([translateYProperty, values[0]]);
|
||||
}
|
||||
break;
|
||||
case "rotate":
|
||||
@ -1546,7 +1546,6 @@ backgroundImageProperty.register(Style);
|
||||
|
||||
export const backgroundColorProperty = new CssProperty<Style, Color>({
|
||||
name: "backgroundColor", cssName: "background-color", valueChanged: (target, oldValue, newValue) => {
|
||||
printUnregisteredProperties();
|
||||
let background = target.backgroundInternal;
|
||||
target.backgroundInternal = background.withColor(newValue);
|
||||
}, equalityComparer: Color.equals, valueConverter: (value) => new Color(value)
|
||||
@ -1564,7 +1563,8 @@ export namespace BackgroundRepeat {
|
||||
}
|
||||
|
||||
export const backgroundRepeatProperty = new CssProperty<Style, BackgroundRepeat>({
|
||||
name: "backgroundRepeat", cssName: "background-repeat", valueConverter: BackgroundRepeat.parse, valueChanged: (target, oldValue, newValue) => {
|
||||
name: "backgroundRepeat", cssName: "background-repeat", valueConverter: BackgroundRepeat.parse,
|
||||
valueChanged: (target, oldValue, newValue) => {
|
||||
let background = target.backgroundInternal;
|
||||
target.backgroundInternal = background.withRepeat(newValue);
|
||||
}
|
||||
@ -1941,7 +1941,8 @@ export const fontFamilyProperty = new InheritedCssProperty<Style, string>({
|
||||
name: "fontFamily", cssName: "font-family", valueChanged: (target, oldValue, newValue) => {
|
||||
let currentFont = target.fontInternal;
|
||||
if (currentFont.fontFamily !== newValue) {
|
||||
target.fontInternal = currentFont.withFontFamily(newValue);
|
||||
const newFont = currentFont.withFontFamily(newValue);
|
||||
target.fontInternal = Font.equals(Font.default, newFont) ? unsetValue : newFont;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1951,7 +1952,8 @@ export const fontSizeProperty = new InheritedCssProperty<Style, number>({
|
||||
name: "fontSize", cssName: "font-size", valueChanged: (target, oldValue, newValue) => {
|
||||
let currentFont = target.fontInternal;
|
||||
if (currentFont.fontSize !== newValue) {
|
||||
target.fontInternal = currentFont.withFontSize(newValue);
|
||||
const newFont = currentFont.withFontSize(newValue);
|
||||
target.fontInternal = Font.equals(Font.default, newFont) ? unsetValue : newFont;
|
||||
}
|
||||
},
|
||||
valueConverter: (v) => parseFloat(v)
|
||||
@ -1962,7 +1964,8 @@ export const fontStyleProperty = new InheritedCssProperty<Style, FontStyle>({
|
||||
name: "fontStyle", cssName: "font-style", defaultValue: FontStyle.NORMAL, valueConverter: FontStyle.parse, valueChanged: (target, oldValue, newValue) => {
|
||||
let currentFont = target.fontInternal;
|
||||
if (currentFont.fontStyle !== newValue) {
|
||||
target.fontInternal = currentFont.withFontStyle(newValue);
|
||||
const newFont = currentFont.withFontStyle(newValue);
|
||||
target.fontInternal = Font.equals(Font.default, newFont) ? unsetValue : newFont;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1972,7 +1975,8 @@ export const fontWeightProperty = new InheritedCssProperty<Style, FontWeight>({
|
||||
name: "fontWeight", cssName: "font-weight", defaultValue: FontWeight.NORMAL, valueConverter: FontWeight.parse, valueChanged: (target, oldValue, newValue) => {
|
||||
let currentFont = target.fontInternal;
|
||||
if (currentFont.fontWeight !== newValue) {
|
||||
target.fontInternal = currentFont.withFontWeight(newValue);
|
||||
const newFont = currentFont.withFontWeight(newValue);
|
||||
target.fontInternal = Font.equals(Font.default, newFont) ? unsetValue : newFont;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
40
tns-core-modules/ui/definitions.d.ts
vendored
40
tns-core-modules/ui/definitions.d.ts
vendored
@ -3,9 +3,9 @@ declare module "ui/core/view-base" {
|
||||
import {
|
||||
Property, PropertyOptions, CoercibleProperty, CoerciblePropertyOptions,
|
||||
InheritedProperty, CssProperty, CssPropertyOptions, InheritedCssProperty,
|
||||
ShorthandProperty, ShorthandPropertyOptions
|
||||
ShorthandProperty, ShorthandPropertyOptions, unsetValue
|
||||
} from "ui/core/properties";
|
||||
import { Binding, BindingOptions, Bindable } from "ui/core/bindable";
|
||||
import { Binding, BindingOptions } from "ui/core/bindable";
|
||||
import { Style } from "ui/styling/style";
|
||||
import { SelectorCore } from "ui/styling/css-selector";
|
||||
import { isIOS, isAndroid } from "platform";
|
||||
@ -15,7 +15,7 @@ declare module "ui/core/view-base" {
|
||||
|
||||
export {
|
||||
Observable, EventData, KeyframeAnimation,
|
||||
Binding, BindingOptions, Bindable, Style, isIOS, isAndroid, gestureFromString,
|
||||
Binding, BindingOptions, Style, isIOS, isAndroid, gestureFromString,
|
||||
traceEnabled, traceWrite, traceCategories, traceNotifyEvent, isCategorySet
|
||||
};
|
||||
|
||||
@ -28,6 +28,7 @@ declare module "ui/core/view-base" {
|
||||
* Returns an instance of a view (if found), otherwise undefined.
|
||||
*/
|
||||
export function getAncestor(view: ViewBase, criterion: string | Function): ViewBase;
|
||||
|
||||
export function isEventOrGesture(name: string, view: ViewBase): boolean;
|
||||
|
||||
/**
|
||||
@ -38,7 +39,7 @@ declare module "ui/core/view-base" {
|
||||
*/
|
||||
export function getViewById(view: ViewBase, id: string): ViewBase;
|
||||
|
||||
export class ViewBase extends Observable {
|
||||
export abstract class ViewBase extends Observable {
|
||||
/**
|
||||
* String value used when hooking to loaded event.
|
||||
*/
|
||||
@ -69,11 +70,6 @@ declare module "ui/core/view-base" {
|
||||
*/
|
||||
public id: string;
|
||||
|
||||
/**
|
||||
* Returns the child view with the specified id.
|
||||
*/
|
||||
public getViewById<T extends ViewBase>(id: string): T;
|
||||
|
||||
/**
|
||||
* Gets or sets the CSS class name for this view.
|
||||
*/
|
||||
@ -101,6 +97,11 @@ declare module "ui/core/view-base" {
|
||||
public isCollapsed: boolean;
|
||||
public readonly isLoaded: boolean;
|
||||
|
||||
/**
|
||||
* Returns the child view with the specified id.
|
||||
*/
|
||||
public getViewById<T extends ViewBase>(id: string): T;
|
||||
|
||||
public onLoaded(): void;
|
||||
public onUnloaded(): void;
|
||||
|
||||
@ -157,6 +158,7 @@ declare module "ui/core/view-base" {
|
||||
_resetNativeView(): void;
|
||||
|
||||
_isAddedToNativeVisualTree: boolean;
|
||||
|
||||
/**
|
||||
* Performs the core logic of adding a child view to the native visual tree. Returns true if the view's native representation has been successfully added, false otherwise.
|
||||
*/
|
||||
@ -187,17 +189,19 @@ declare module "ui/core/view-base" {
|
||||
declare module "ui/core/properties" {
|
||||
import { ViewBase } from "ui/core/view-base";
|
||||
import { Style } from "ui/styling/style";
|
||||
import { unsetValue } from "ui/core/dependency-observable";
|
||||
|
||||
export { unsetValue };
|
||||
|
||||
/**
|
||||
* Value specifing that Property should be set to its initial value.
|
||||
*/
|
||||
export const unsetValue: any;
|
||||
|
||||
export interface PropertyOptions<T, U> {
|
||||
readonly name: string,
|
||||
readonly defaultValue?: U,
|
||||
readonly affectsLayout?: boolean,
|
||||
readonly equalityComparer?: (x: U, y: U) => boolean,
|
||||
readonly valueChanged?: (target: T, oldValue: U, newValue: U) => void,
|
||||
readonly valueConverter?: (value: string) => U
|
||||
readonly name: string;
|
||||
readonly defaultValue?: U;
|
||||
readonly affectsLayout?: boolean;
|
||||
readonly equalityComparer?: (x: U, y: U) => boolean;
|
||||
readonly valueChanged?: (target: T, oldValue: U, newValue: U) => void;
|
||||
readonly valueConverter?: (value: string) => U;
|
||||
}
|
||||
|
||||
export interface CoerciblePropertyOptions<T, U> extends PropertyOptions<T, U> {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {
|
||||
SearchBarBase, Font, Color, colorProperty, backgroundColorProperty, backgroundInternalProperty, fontInternalProperty,
|
||||
textProperty, hintProperty, textFieldHintColorProperty, textFieldBackgroundColorProperty
|
||||
textProperty, hintProperty, textFieldHintColorProperty, textFieldBackgroundColorProperty, fontSizeProperty
|
||||
} from "./search-bar-common";
|
||||
import { ad } from "utils/utils";
|
||||
|
||||
@ -128,34 +128,28 @@ export class SearchBar extends SearchBarBase {
|
||||
textView.setTextColor(color);
|
||||
}
|
||||
|
||||
get [fontInternalProperty.native](): { typeface: android.graphics.Typeface, fontSize: number } {
|
||||
let textView = this._getTextView();
|
||||
return {
|
||||
typeface: textView.getTypeface(),
|
||||
fontSize: textView.getTextSize()
|
||||
};
|
||||
get [fontSizeProperty.native](): { nativeSize: number } {
|
||||
return { nativeSize: this._getTextView().getTextSize() };
|
||||
}
|
||||
set [fontInternalProperty.native](value: Font | { typeface: android.graphics.Typeface, fontSize: number }) {
|
||||
let textView = this._getTextView();
|
||||
|
||||
if (value instanceof Font) {
|
||||
// Set value
|
||||
textView.setTypeface(value.getAndroidTypeface());
|
||||
if (value.fontSize !== undefined){
|
||||
textView.setTextSize(value.fontSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Reset value
|
||||
textView.setTypeface(value.typeface);
|
||||
textView.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.fontSize);
|
||||
set [fontSizeProperty.native](value: number | { nativeSize: number }) {
|
||||
if (typeof value === "number") {
|
||||
this._getTextView().setTextSize(value);
|
||||
} else {
|
||||
this._getTextView().setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
|
||||
}
|
||||
}
|
||||
|
||||
get [backgroundInternalProperty.native](): Font {
|
||||
get [fontInternalProperty.native](): android.graphics.Typeface {
|
||||
return this._getTextView().getTypeface();
|
||||
}
|
||||
set [fontInternalProperty.native](value: Font | android.graphics.Typeface) {
|
||||
this._getTextView().setTypeface(value instanceof Font ? value.getAndroidTypeface() : value);
|
||||
}
|
||||
|
||||
get [backgroundInternalProperty.native](): any {
|
||||
return null;
|
||||
}
|
||||
set [backgroundInternalProperty.native](value: Font) {
|
||||
set [backgroundInternalProperty.native](value: any) {
|
||||
//
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {
|
||||
SegmentedBarItemBase, SegmentedBarBase, selectedIndexProperty, itemsProperty, selectedBackgroundColorProperty,
|
||||
colorProperty, fontInternalProperty, Color, Font, applyNativeSetters
|
||||
colorProperty, fontInternalProperty, fontSizeProperty, Color, Font, applyNativeSetters
|
||||
} from "./segmented-bar-common";
|
||||
|
||||
export * from "./segmented-bar-common";
|
||||
@ -96,29 +96,24 @@ export class SegmentedBarItem extends SegmentedBarItemBase {
|
||||
this._textView.setTextColor(color);
|
||||
}
|
||||
|
||||
get [fontInternalProperty.native](): { typeface: android.graphics.Typeface, fontSize: number } {
|
||||
let textView = this._textView;
|
||||
return {
|
||||
typeface: textView.getTypeface(),
|
||||
fontSize: textView.getTextSize()
|
||||
};
|
||||
get [fontSizeProperty.native](): { nativeSize: number } {
|
||||
return { nativeSize: this._textView.getTextSize() };
|
||||
}
|
||||
set [fontInternalProperty.native](value: Font | { typeface: android.graphics.Typeface, fontSize: number }) {
|
||||
let textView = this._textView;
|
||||
if (value instanceof Font) {
|
||||
// Set value
|
||||
textView.setTypeface(value.getAndroidTypeface());
|
||||
if (value.fontSize !== undefined) {
|
||||
textView.setTextSize(value.fontSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Reset value
|
||||
textView.setTypeface(value.typeface);
|
||||
textView.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.fontSize);
|
||||
set [fontSizeProperty.native](value: number | { nativeSize: number }) {
|
||||
if (typeof value === "number") {
|
||||
this._textView.setTextSize(value);
|
||||
} else {
|
||||
this._textView.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
|
||||
}
|
||||
}
|
||||
|
||||
get [fontInternalProperty.native](): android.graphics.Typeface {
|
||||
return this._textView.getTypeface();
|
||||
}
|
||||
set [fontInternalProperty.native](value: Font | android.graphics.Typeface) {
|
||||
this._textView.setTypeface(value instanceof Font ? value.getAndroidTypeface() : value);
|
||||
}
|
||||
|
||||
get [selectedBackgroundColorProperty.native](): android.graphics.drawable.Drawable {
|
||||
let viewGroup = <android.view.ViewGroup>this._textView.getParent();
|
||||
return viewGroup.getBackground();
|
||||
|
@ -44,8 +44,7 @@ export class Font extends FontBase {
|
||||
fontStyle |= android.graphics.Typeface.ITALIC;
|
||||
}
|
||||
|
||||
const typeFace = createTypeface(this);
|
||||
this._typeface = android.graphics.Typeface.create(typeFace, fontStyle);
|
||||
this._typeface = createTypeface(this, fontStyle);
|
||||
}
|
||||
return this._typeface;
|
||||
}
|
||||
@ -96,7 +95,7 @@ function loadFontFromFile(fontFamily: string): android.graphics.Typeface {
|
||||
return result;
|
||||
}
|
||||
|
||||
function createTypeface(font: Font): android.graphics.Typeface {
|
||||
function createTypeface(font: Font, fontStyle: number): android.graphics.Typeface {
|
||||
//http://stackoverflow.com/questions/19691530/valid-values-for-androidfontfamily-and-what-they-map-to
|
||||
const fonts = parseFontFamily(font.fontFamily);
|
||||
let result = null;
|
||||
@ -107,16 +106,16 @@ function createTypeface(font: Font): android.graphics.Typeface {
|
||||
for (let i = 0; i < fonts.length; i++) {
|
||||
switch (fonts[i].toLowerCase()) {
|
||||
case genericFontFamilies.serif:
|
||||
result = android.graphics.Typeface.create("serif" + getFontWeightSuffix(font.fontWeight), 0);
|
||||
result = android.graphics.Typeface.create("serif" + getFontWeightSuffix(font.fontWeight), fontStyle);
|
||||
break;
|
||||
|
||||
case genericFontFamilies.sansSerif:
|
||||
case genericFontFamilies.system:
|
||||
result = android.graphics.Typeface.create("sans-serif" + getFontWeightSuffix(font.fontWeight), 0);
|
||||
result = android.graphics.Typeface.create("sans-serif" + getFontWeightSuffix(font.fontWeight), fontStyle);
|
||||
break;
|
||||
|
||||
case genericFontFamilies.monospace:
|
||||
result = android.graphics.Typeface.create("monospace" + getFontWeightSuffix(font.fontWeight), 0);
|
||||
result = android.graphics.Typeface.create("monospace" + getFontWeightSuffix(font.fontWeight), fontStyle);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
4
tns-core-modules/ui/styling/font.d.ts
vendored
4
tns-core-modules/ui/styling/font.d.ts
vendored
@ -10,7 +10,7 @@
|
||||
public isBold: boolean;
|
||||
public isItalic: boolean;
|
||||
|
||||
constructor(family: string, size: number, style: string, weight: string);
|
||||
constructor(family: string, size: number, style: FontStyle, weight: FontWeight);
|
||||
|
||||
public getAndroidTypeface(): any /* android.graphics.Typeface */;
|
||||
public getUIFont(defaultFont: any /* UIFont */): any /* UIFont */;
|
||||
@ -60,4 +60,4 @@
|
||||
export module ios {
|
||||
export function registerFont(fontFile: string);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,8 @@ import {
|
||||
TabViewBase, TabViewItemBase, itemsProperty, selectedIndexProperty,
|
||||
tabTextColorProperty, tabBackgroundColorProperty, selectedTabTextColorProperty,
|
||||
androidSelectedTabHighlightColorProperty, androidOffscreenTabLimitProperty,
|
||||
fontInternalProperty, traceCategory, View, layout, Color, Font, traceEnabled, traceWrite,
|
||||
fontSizeProperty, fontInternalProperty, View, layout, Color, Font,
|
||||
traceCategory, traceEnabled, traceWrite,
|
||||
applyNativeSetters
|
||||
} from "./tab-view-common"
|
||||
import { textTransformProperty, TextTransform, getTransformedText } from "ui/text-base";
|
||||
@ -36,36 +37,22 @@ export class TabViewItem extends TabViewItemBase {
|
||||
}
|
||||
}
|
||||
|
||||
get [fontInternalProperty.native](): { typeface: android.graphics.Typeface, fontSize: number } {
|
||||
const tv = this.nativeView;
|
||||
return {
|
||||
typeface: tv.getTypeface(),
|
||||
fontSize: tv.getTextSize()
|
||||
};
|
||||
get [fontSizeProperty.native](): { nativeSize: number } {
|
||||
return { nativeSize: this.nativeView.getTextSize() };
|
||||
}
|
||||
set [fontInternalProperty.native](value: Font | { typeface: android.graphics.Typeface, fontSize: number }) {
|
||||
let typeface: android.graphics.Typeface;
|
||||
let isFont: boolean;
|
||||
const fontSize = value.fontSize;
|
||||
if (value instanceof Font) {
|
||||
isFont = true;
|
||||
typeface = value.getAndroidTypeface();
|
||||
}
|
||||
else {
|
||||
typeface = value.typeface;
|
||||
set [fontSizeProperty.native](value: number | { nativeSize: number }) {
|
||||
if (typeof value === "number") {
|
||||
this.nativeView.setTextSize(value);
|
||||
} else {
|
||||
this.nativeView.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.nativeSize);
|
||||
}
|
||||
}
|
||||
|
||||
const tv = this.nativeView;
|
||||
tv.setTypeface(typeface);
|
||||
|
||||
if (isFont) {
|
||||
if (fontSize !== undefined) {
|
||||
tv.setTextSize(fontSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, fontSize);
|
||||
}
|
||||
get [fontInternalProperty.native](): android.graphics.Typeface {
|
||||
return this.nativeView.getTypeface();
|
||||
}
|
||||
set [fontInternalProperty.native](value: Font | android.graphics.Typeface) {
|
||||
this.nativeView.setTypeface(value instanceof Font ? value.getAndroidTypeface() : value);
|
||||
}
|
||||
|
||||
get [textTransformProperty.native](): TextTransform {
|
||||
@ -269,7 +256,7 @@ export class TabView extends TabViewBase {
|
||||
|
||||
public onItemsChanged(oldItems: TabViewItem[], newItems: TabViewItem[]): void {
|
||||
super.onItemsChanged(oldItems, newItems);
|
||||
|
||||
|
||||
if (oldItems) {
|
||||
oldItems.forEach((item: TabViewItem, i, arr) => {
|
||||
item.index = 0;
|
||||
|
@ -1,13 +1,16 @@
|
||||
import { TextBase as TextBaseDefinition } from "ui/text-base";
|
||||
import { View, Property, CssProperty, InheritedCssProperty, Style, isIOS, Observable, makeValidator, makeParser, Length } from "ui/core/view";
|
||||
import { PropertyChangeData } from "data/observable";
|
||||
import { FormattedString, FormattedStringView } from "text/formatted-string";
|
||||
import { addWeakEventListener, removeWeakEventListener } from "ui/core/weak-event-listener";
|
||||
import { FormattedString, Span } from "text/formatted-string";
|
||||
|
||||
export { FormattedString };
|
||||
export { FormattedString, Span };
|
||||
export * from "ui/core/view";
|
||||
|
||||
export abstract class TextBaseCommon extends View implements TextBaseDefinition, FormattedStringView {
|
||||
const CHILD_SPAN = "Span";
|
||||
const CHILD_FORMATTED_TEXT = "formattedText";
|
||||
const CHILD_FORMATTED_STRING = "FormattedString";
|
||||
|
||||
export abstract class TextBaseCommon extends View implements TextBaseDefinition {
|
||||
|
||||
// public abstract _setFormattedTextPropertyToNative(value: FormattedString): void;
|
||||
|
||||
@ -92,18 +95,25 @@ export abstract class TextBaseCommon extends View implements TextBaseDefinition,
|
||||
}
|
||||
|
||||
public _onFormattedTextContentsChanged(data: PropertyChangeData) {
|
||||
if (this._nativeView){
|
||||
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 {
|
||||
if (!this.formattedText) {
|
||||
this.formattedText = new FormattedString();
|
||||
if (name === CHILD_SPAN) {
|
||||
if (!this.formattedText) {
|
||||
const formattedText = new FormattedString();
|
||||
formattedText.spans.push(value);
|
||||
this.formattedText = formattedText;
|
||||
} else {
|
||||
this.formattedText.spans.push(value);
|
||||
}
|
||||
}
|
||||
else if (name === CHILD_FORMATTED_TEXT || name === CHILD_FORMATTED_STRING) {
|
||||
this.formattedText = value;
|
||||
}
|
||||
|
||||
FormattedString.addFormattedStringToView(this, name, value);
|
||||
}
|
||||
|
||||
_requestLayoutOnTextChanged(): void {
|
||||
@ -125,13 +135,13 @@ formattedTextProperty.register(TextBaseCommon);
|
||||
|
||||
function onFormattedTextPropertyChanged(textBase: TextBaseCommon, oldValue: FormattedString, newValue: FormattedString) {
|
||||
if (oldValue) {
|
||||
oldValue.parent = null;
|
||||
removeWeakEventListener(oldValue, Observable.propertyChangeEvent, textBase._onFormattedTextContentsChanged, textBase);
|
||||
oldValue.off(Observable.propertyChangeEvent, textBase._onFormattedTextContentsChanged, textBase);
|
||||
textBase._removeView(oldValue);
|
||||
}
|
||||
|
||||
if (newValue) {
|
||||
newValue.parent = textBase;
|
||||
addWeakEventListener(newValue, Observable.propertyChangeEvent, textBase._onFormattedTextContentsChanged, textBase);
|
||||
textBase._addView(newValue);
|
||||
newValue.on(Observable.propertyChangeEvent, textBase._onFormattedTextContentsChanged, textBase);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,15 @@
|
||||
TextBaseCommon, formattedTextProperty, textAlignmentProperty, textDecorationProperty, fontSizeProperty,
|
||||
textProperty, textTransformProperty, letterSpacingProperty, colorProperty, fontInternalProperty,
|
||||
whiteSpaceProperty, Font, Color, FormattedString, TextDecoration, TextAlignment, TextTransform, WhiteSpace,
|
||||
paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, Length
|
||||
paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, Length,
|
||||
layout, Span
|
||||
} from "./text-base-common";
|
||||
import { toUIString } from "utils/types";
|
||||
|
||||
import { FontWeight, FontStyle } from "ui/styling/font";
|
||||
|
||||
export * from "./text-base-common";
|
||||
|
||||
export class TextBase extends TextBaseCommon {
|
||||
_transformationMethod: any;
|
||||
_nativeView: android.widget.TextView;
|
||||
|
||||
//Text
|
||||
@ -26,18 +28,17 @@ export class TextBase extends TextBaseCommon {
|
||||
}
|
||||
set [formattedTextProperty.native](value: FormattedString) {
|
||||
let spannableStringBuilder = createSpannableStringBuilder(value);
|
||||
const text = (spannableStringBuilder === null || spannableStringBuilder === undefined) ? '' : <any>spannableStringBuilder;
|
||||
this._nativeView.setText(text);
|
||||
this._nativeView.setText(<any>spannableStringBuilder);
|
||||
textProperty.nativeValueChange(this, (value === null || value === undefined) ? '' : value.toString());
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,24 +79,11 @@ export class TextBase extends TextBaseCommon {
|
||||
}
|
||||
|
||||
//FontInternal
|
||||
get [fontInternalProperty.native](): { typeface: android.graphics.Typeface, fontSize: number } {
|
||||
let textView = this._nativeView;
|
||||
return {
|
||||
typeface: textView.getTypeface(),
|
||||
fontSize: textView.getTextSize()
|
||||
};
|
||||
get [fontInternalProperty.native](): android.graphics.Typeface {
|
||||
return this._nativeView.getTypeface();
|
||||
}
|
||||
set [fontInternalProperty.native](value: Font | { typeface: android.graphics.Typeface, fontSize: number }) {
|
||||
let textView = this._nativeView;
|
||||
if (value instanceof Font) {
|
||||
// Set value. Note: Size is handled in fontSizeProperty.native
|
||||
textView.setTypeface(value.getAndroidTypeface());
|
||||
}
|
||||
else {
|
||||
// Reset value. Note: Resetting fontInternal will reset the size also.
|
||||
textView.setTypeface(value.typeface);
|
||||
textView.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, value.fontSize);
|
||||
}
|
||||
set [fontInternalProperty.native](value: Font | android.graphics.Typeface) {
|
||||
this._nativeView.setTypeface(value instanceof Font ? value.getAndroidTypeface() : value);
|
||||
}
|
||||
|
||||
//TextAlignment
|
||||
@ -176,6 +164,7 @@ export class TextBase extends TextBaseCommon {
|
||||
}
|
||||
}
|
||||
|
||||
//LetterSpacing
|
||||
get [letterSpacingProperty.native](): number {
|
||||
return org.nativescript.widgets.ViewHelper.getLetterspacing(this._nativeView);
|
||||
}
|
||||
@ -224,7 +213,7 @@ class TextTransformation extends android.text.method.ReplacementTransformationMe
|
||||
}
|
||||
|
||||
protected getOriginal(): native.Array<string> {
|
||||
return convertStringToNativeCharArray(this.formattedText ? this.formattedText.toString() : this.originalText);
|
||||
return convertStringToNativeCharArray(this.formattedText ? this.formattedText.toString() : this.originalText);
|
||||
}
|
||||
|
||||
protected getReplacement(): native.Array<string> {
|
||||
@ -239,7 +228,7 @@ class TextTransformation extends android.text.method.ReplacementTransformationMe
|
||||
replacementString = getTransformedText(this.originalText, this.textTransform);
|
||||
}
|
||||
|
||||
return convertStringToNativeCharArray(replacementString);
|
||||
return convertStringToNativeCharArray(replacementString);
|
||||
}
|
||||
|
||||
public getTransformation(charSeq: any, view: android.view.View): any {
|
||||
@ -281,26 +270,23 @@ function getTransformedText(text: string, textTransform: TextTransform): string
|
||||
function createSpannableStringBuilder(formattedString: FormattedString): android.text.SpannableStringBuilder {
|
||||
let ssb = new android.text.SpannableStringBuilder();
|
||||
|
||||
if (formattedString === null || formattedString === undefined){
|
||||
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);
|
||||
}
|
||||
for (let i = 0, spanStart = 0, spanLength = 0, length = formattedString.spans.length; i < length; i++) {
|
||||
const span = formattedString.spans.getItem(i);
|
||||
const text = span.text;
|
||||
const textTransform = (<TextBase>formattedString.parent).textTransform;
|
||||
let spanText = (text === null || text === undefined) ? '' : text.toString();
|
||||
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);
|
||||
}
|
||||
setSpanModifiers(ssb, span, spanStart, spanStart + spanLength);
|
||||
spanStart += spanLength;
|
||||
}
|
||||
}
|
||||
@ -315,3 +301,105 @@ function convertStringToNativeCharArray(value: string): native.Array<string> {
|
||||
}
|
||||
return nativeCharArray;
|
||||
}
|
||||
|
||||
function isBold(fontWeight: FontWeight): boolean {
|
||||
return fontWeight === FontWeight.BOLD
|
||||
|| fontWeight === "700"
|
||||
|| fontWeight === FontWeight.EXTRA_BOLD
|
||||
|| fontWeight === FontWeight.BLACK;
|
||||
}
|
||||
|
||||
function setSpanModifiers(ssb: android.text.SpannableStringBuilder, span: Span, start: number, end: number): void {
|
||||
const style = span.style;
|
||||
const bold = isBold(style.fontWeight);
|
||||
const italic = style.fontStyle === FontStyle.ITALIC;
|
||||
|
||||
if (bold && italic) {
|
||||
ssb.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD_ITALIC), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
else if (bold) {
|
||||
ssb.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
else if (italic) {
|
||||
ssb.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.ITALIC), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
const fontFamily = span.fontFamily;
|
||||
if (fontFamily) {
|
||||
const font = new Font(fontFamily, 0, (italic) ? "italic" : "normal", (bold) ? "bold" : "normal");
|
||||
ensureCustomTypefaceSpanClass();
|
||||
const typefaceSpan: android.text.style.TypefaceSpan = new CustomTypefaceSpanClass(fontFamily, font.getAndroidTypeface());
|
||||
ssb.setSpan(typefaceSpan, start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
const realFontSize = span.fontSize;
|
||||
if (realFontSize) {
|
||||
ssb.setSpan(new android.text.style.AbsoluteSizeSpan(realFontSize * layout.getDisplayDensity()), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
const color = span.color;
|
||||
if (color) {
|
||||
ssb.setSpan(new android.text.style.ForegroundColorSpan(color.android), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
const backgroundColor = style.backgroundColor || (<FormattedString>span.parent).backgroundColor || (<TextBase>(<FormattedString>span.parent).parent).backgroundColor;
|
||||
if (backgroundColor) {
|
||||
ssb.setSpan(new android.text.style.BackgroundColorSpan(backgroundColor.android), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
const textDecorations = style.textDecoration || (<FormattedString>span.parent).textDecoration || (<TextBase>(<FormattedString>span.parent).parent).textDecoration;
|
||||
const underline = textDecorations.indexOf(TextDecoration.UNDERLINE) !== -1;
|
||||
if (underline) {
|
||||
ssb.setSpan(new android.text.style.UnderlineSpan(), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
const strikethrough = textDecorations.indexOf(TextDecoration.LINE_THROUGH) !== -1;
|
||||
if (strikethrough) {
|
||||
ssb.setSpan(new android.text.style.StrikethroughSpan(), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
|
||||
var CustomTypefaceSpanClass;
|
||||
function ensureCustomTypefaceSpanClass() {
|
||||
if (CustomTypefaceSpanClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Move this class in widgets.
|
||||
class CustomTypefaceSpan extends android.text.style.TypefaceSpan {
|
||||
private typeface: android.graphics.Typeface;
|
||||
|
||||
constructor(family: string, typeface: android.graphics.Typeface) {
|
||||
super(family);
|
||||
this.typeface = typeface;
|
||||
return global.__native(this);
|
||||
}
|
||||
|
||||
public updateDrawState(ds: android.text.TextPaint): void {
|
||||
this.applyCustomTypeFace(ds);
|
||||
}
|
||||
|
||||
public updateMeasureState(paint: android.text.TextPaint): void {
|
||||
this.applyCustomTypeFace(paint);
|
||||
}
|
||||
|
||||
private applyCustomTypeFace(paint: android.text.TextPaint) {
|
||||
const old = paint.getTypeface();
|
||||
const oldStyle = old === null ? 0 : old.getStyle();
|
||||
|
||||
const typeface = this.typeface;
|
||||
let fake = oldStyle & ~typeface.getStyle();
|
||||
if ((fake & android.graphics.Typeface.BOLD) !== 0) {
|
||||
paint.setFakeBoldText(true);
|
||||
}
|
||||
|
||||
if ((fake & android.graphics.Typeface.ITALIC) !== 0) {
|
||||
paint.setTextSkewX(-0.25);
|
||||
}
|
||||
|
||||
paint.setTypeface(typeface);
|
||||
}
|
||||
}
|
||||
|
||||
CustomTypefaceSpanClass = CustomTypefaceSpan;
|
||||
}
|
@ -1,15 +1,20 @@
|
||||
import {
|
||||
TextBaseCommon, textProperty, formattedTextProperty, textAlignmentProperty, textDecorationProperty,
|
||||
textTransformProperty, letterSpacingProperty, colorProperty, fontInternalProperty, Font, Color, FormattedString,
|
||||
TextDecoration, TextAlignment, TextTransform
|
||||
TextDecoration, TextAlignment, TextTransform, Span
|
||||
} from "./text-base-common";
|
||||
|
||||
import { FontWeight, FontStyle } from "ui/styling/font";
|
||||
import * as utils from "utils/utils";
|
||||
import { toUIString } from "utils/types";
|
||||
|
||||
export * from "./text-base-common";
|
||||
|
||||
export class TextBase extends TextBaseCommon {
|
||||
|
||||
private textDecorationSet: boolean;
|
||||
private textTransformSet: boolean;
|
||||
private letterSpacingSet: boolean;
|
||||
|
||||
public nativeView: UITextField | UITextView | UILabel | UIButton;
|
||||
|
||||
//Text
|
||||
@ -22,21 +27,17 @@ export class TextBase extends TextBaseCommon {
|
||||
}
|
||||
}
|
||||
set [textProperty.native](value: string) {
|
||||
let newValue = (value === undefined || value === null) ? '' : value.toString();
|
||||
let nativeView = this.nativeView;
|
||||
if (nativeView instanceof UIButton) {
|
||||
const newValue = (value === undefined || value === null) ? '' : value.toString();
|
||||
const nativeView = this.nativeView;
|
||||
if (this.textDecorationSet || this.textTransformSet || this.letterSpacingSet) {
|
||||
const style = this.style;
|
||||
setTextDecorationAndTransform(newValue, nativeView, style.textDecoration, style.textTransform, style.letterSpacing, style.color);
|
||||
} else if (nativeView instanceof UIButton) {
|
||||
nativeView.setTitleForState(newValue, UIControlState.Normal);
|
||||
|
||||
//https://github.com/NativeScript/NativeScript/issues/2615
|
||||
let attributedTitle = nativeView.attributedTitleForState(UIControlState.Normal);
|
||||
if (attributedTitle !== null) {
|
||||
let style = this.style;
|
||||
setTextDecorationAndTransform(newValue, this.nativeView, style.textDecoration, style.textTransform, style.letterSpacing, style.color);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
nativeView.text = newValue;
|
||||
}
|
||||
|
||||
this._requestLayoutOnTextChanged();
|
||||
}
|
||||
|
||||
@ -45,15 +46,9 @@ export class TextBase extends TextBaseCommon {
|
||||
return null;
|
||||
}
|
||||
set [formattedTextProperty.native](value: FormattedString) {
|
||||
let mas = createNSMutableAttributedString(value);
|
||||
let nativeView = this.nativeView;
|
||||
if (nativeView instanceof UIButton) {
|
||||
nativeView.setAttributedTitleForState(mas, UIControlState.Normal);
|
||||
}
|
||||
else {
|
||||
nativeView.attributedText = mas;
|
||||
}
|
||||
textProperty.nativeValueChange(this, (value === null || value === undefined) ? '' : value.toString());
|
||||
const style = this.style;
|
||||
setFormattedTextDecorationAndTransform(value, this.nativeView, style.textDecoration, style.textTransform, style.letterSpacing);
|
||||
textProperty.nativeValueChange(this, !value ? '' : value.toString());
|
||||
}
|
||||
|
||||
//Color
|
||||
@ -80,7 +75,7 @@ export class TextBase extends TextBaseCommon {
|
||||
nativeView = nativeView instanceof UIButton ? nativeView.titleLabel : nativeView;
|
||||
return nativeView.font;
|
||||
}
|
||||
set [fontInternalProperty.native](value: Font) {
|
||||
set [fontInternalProperty.native](value: Font | UIFont) {
|
||||
let nativeView = this.nativeView;
|
||||
nativeView = nativeView instanceof UIButton ? nativeView.titleLabel : nativeView;
|
||||
let font = value instanceof Font ? value.getUIFont(nativeView.font) : value;
|
||||
@ -127,6 +122,7 @@ export class TextBase extends TextBaseCommon {
|
||||
return TextDecoration.NONE;
|
||||
}
|
||||
set [textDecorationProperty.native](value: TextDecoration) {
|
||||
this.textDecorationSet = value !== TextDecoration.NONE;
|
||||
if (this.formattedText) {
|
||||
setFormattedTextDecorationAndTransform(this.formattedText, this.nativeView, value, this.style.textTransform, this.style.letterSpacing);
|
||||
} else {
|
||||
@ -139,6 +135,7 @@ export class TextBase extends TextBaseCommon {
|
||||
return TextTransform.NONE;
|
||||
}
|
||||
set [textTransformProperty.native](value: TextTransform) {
|
||||
this.textTransformSet = value !== TextTransform.NONE;
|
||||
if (this.formattedText) {
|
||||
setFormattedTextDecorationAndTransform(this.formattedText, this.nativeView, this.style.textDecoration, value, this.style.letterSpacing);
|
||||
} else {
|
||||
@ -151,6 +148,7 @@ export class TextBase extends TextBaseCommon {
|
||||
return Number.NaN;
|
||||
}
|
||||
set [letterSpacingProperty.native](value: number) {
|
||||
this.letterSpacingSet = value !== 0;
|
||||
if (this.formattedText) {
|
||||
setFormattedTextDecorationAndTransform(this.formattedText, this.nativeView, this.style.textDecoration, this.style.textTransform, value);
|
||||
} else {
|
||||
@ -178,55 +176,18 @@ function NSStringFromNSAttributedString(source: NSAttributedString | string): NS
|
||||
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);
|
||||
|
||||
const attrText = createNSMutableAttributedString(formattedText);
|
||||
const hasLetterSpacing = typeof letterSpacing === "number" && !isNaN(letterSpacing) && letterSpacing !== 0;
|
||||
if (hasLetterSpacing) {
|
||||
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;
|
||||
}
|
||||
attrText.addAttributeValueRange(NSKernAttributeName, letterSpacing * nativeView.font.pointSize, { location: 0, length: attrText.length });
|
||||
}
|
||||
|
||||
if (nativeView instanceof UIButton) {
|
||||
nativeView.setAttributedTitleForState(attrText, UIControlState.Normal);
|
||||
}
|
||||
else {
|
||||
nativeView.attributedText = attrText;
|
||||
}
|
||||
}
|
||||
|
||||
@ -284,19 +245,91 @@ function setTextDecorationAndTransform(text: string, nativeView: UITextField | U
|
||||
function createNSMutableAttributedString(formattedString: FormattedString): NSMutableAttributedString {
|
||||
let mas = NSMutableAttributedString.alloc().init();
|
||||
if (formattedString) {
|
||||
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);
|
||||
for (let i = 0, spanStart = 0, spanLength = 0, length = formattedString.spans.length; i < length; i++) {
|
||||
const span = formattedString.spans.getItem(i);
|
||||
const text = span.text;
|
||||
const textTransform = (<TextBase>formattedString.parent).textTransform;
|
||||
let spanText = (text === null || text === undefined) ? '' : text.toString();
|
||||
if (textTransform) {
|
||||
spanText = getTransformedText(spanText, textTransform);
|
||||
}
|
||||
let nsAttributedString = NSMutableAttributedString.alloc().initWithStringAttributes(String(spanText), attrDict);
|
||||
|
||||
spanLength = spanText.length;
|
||||
const nsAttributedString = createMutableStringForSpan(span, spanText);
|
||||
mas.insertAttributedStringAtIndex(nsAttributedString, spanStart);
|
||||
spanStart += spanLength;
|
||||
}
|
||||
}
|
||||
return mas;
|
||||
}
|
||||
|
||||
function isBold(fontWeight: FontWeight): boolean {
|
||||
return fontWeight === FontWeight.BOLD
|
||||
|| fontWeight === "700"
|
||||
|| fontWeight === FontWeight.EXTRA_BOLD
|
||||
|| fontWeight === FontWeight.BLACK;
|
||||
}
|
||||
|
||||
function createMutableStringForSpan(span: Span, text: string): NSMutableAttributedString {
|
||||
let attrDict = <{ key: string, value: any }>{};
|
||||
const style = span.style;
|
||||
const bold = isBold(style.fontWeight);
|
||||
const italic = style.fontStyle === FontStyle.ITALIC;
|
||||
|
||||
let fontFamily = span.fontFamily;
|
||||
let fontSize = span.fontSize;
|
||||
|
||||
if (bold || italic || fontFamily || fontSize) {
|
||||
let font;
|
||||
if (fontFamily) {
|
||||
if (!fontSize) {
|
||||
fontSize = utils.ios.getter(UIFont, UIFont.systemFontSize);
|
||||
}
|
||||
|
||||
font = UIFont.fontWithNameSize(fontFamily, fontSize);
|
||||
}
|
||||
|
||||
if (!font) {
|
||||
const fontDescriptor = UIFontDescriptor.new();
|
||||
let symbolicTraits;
|
||||
if (bold) {
|
||||
symbolicTraits |= UIFontDescriptorSymbolicTraits.TraitBold;
|
||||
}
|
||||
|
||||
if (italic) {
|
||||
symbolicTraits |= UIFontDescriptorSymbolicTraits.TraitItalic;
|
||||
}
|
||||
|
||||
font = UIFont.fontWithDescriptorSize(fontDescriptor.fontDescriptorWithSymbolicTraits(symbolicTraits), fontSize);
|
||||
}
|
||||
|
||||
attrDict[NSFontAttributeName] = font;
|
||||
}
|
||||
|
||||
const color = span.color;
|
||||
if (color) {
|
||||
attrDict[NSForegroundColorAttributeName] = color.ios;
|
||||
}
|
||||
|
||||
const backgroundColor = style.backgroundColor
|
||||
|| (<FormattedString>span.parent).backgroundColor
|
||||
|| (<TextBase>(<FormattedString>span.parent).parent).backgroundColor;
|
||||
if (backgroundColor) {
|
||||
attrDict[NSBackgroundColorAttributeName] = backgroundColor.ios;
|
||||
}
|
||||
|
||||
const textDecorations = style.textDecoration
|
||||
|| (<FormattedString>span.parent).textDecoration
|
||||
|| (<TextBase>(<FormattedString>span.parent).parent).textDecoration;
|
||||
const underline = textDecorations.indexOf(TextDecoration.UNDERLINE) !== -1;
|
||||
if (underline) {
|
||||
attrDict[NSUnderlineStyleAttributeName] = underline;
|
||||
}
|
||||
|
||||
const strikethrough = textDecorations.indexOf(TextDecoration.LINE_THROUGH) !== -1;
|
||||
if (strikethrough) {
|
||||
attrDict[NSStrikethroughStyleAttributeName] = strikethrough;
|
||||
}
|
||||
|
||||
return NSMutableAttributedString.alloc().initWithStringAttributes(text, <any>attrDict);
|
||||
}
|
Reference in New Issue
Block a user