From 45394f9672724caab8b8e58e5f0236f7b7786c2f Mon Sep 17 00:00:00 2001 From: Vladimir Enchev Date: Thu, 5 Nov 2015 16:00:10 +0200 Subject: [PATCH 01/15] initial commit --- apps/gallery-app/app.css | 6 ++++- ui/enums/enums.d.ts | 25 ++++++++++++++++++ ui/enums/enums.ts | 7 +++++ ui/styling/converters.ts | 14 ++++++++++ ui/styling/style.d.ts | 2 ++ ui/styling/style.ts | 20 ++++++++++++++ ui/styling/stylers.ios.ts | 46 +++++++++++++++++++++++++++++++++ ui/styling/styling.d.ts | 1 + ui/text-base/text-base.ts | 2 ++ ui/text-field/text-field.ios.ts | 3 +++ ui/text-view/text-view.ios.ts | 4 +++ 11 files changed, 129 insertions(+), 1 deletion(-) diff --git a/apps/gallery-app/app.css b/apps/gallery-app/app.css index 0dc6af8bc..569d88605 100644 --- a/apps/gallery-app/app.css +++ b/apps/gallery-app/app.css @@ -19,4 +19,8 @@ ActionBar, TabView, ActivityIndicator, Label, Button, TextView, TextField, Searc Switch, Progress, Slider, SegmentedBar { color: mediumaquamarine; background-color: aquamarine; -}*/ \ No newline at end of file +}*/ + +TextView, TextField, Label, Button { + text-decoration: underline; +} \ No newline at end of file diff --git a/ui/enums/enums.d.ts b/ui/enums/enums.d.ts index 997b6c8b6..2eada7b88 100644 --- a/ui/enums/enums.d.ts +++ b/ui/enums/enums.d.ts @@ -417,6 +417,31 @@ */ export var italic: string; } + + /** + * Specifies different text decorations. + */ + export module TextDecoration { + /** + * No decoration. + */ + export var none: string; + + /** + * Text decoration underline. + */ + export var underline: string; + + /** + * Text decoration overline. + */ + export var overline: string; + + /** + * Text decoration line-through. + */ + export var lineThrough: string; + } /** diff --git a/ui/enums/enums.ts b/ui/enums/enums.ts index f5b98857a..3b2a409a0 100644 --- a/ui/enums/enums.ts +++ b/ui/enums/enums.ts @@ -20,6 +20,13 @@ export module TextAlignment { export var right = "right"; } +export module TextDecoration { + export var none = "none"; + export var underline = "underline"; + export var overline = "overline"; + export var lineThrough = "lineThrough"; +} + export module Orientation { export var horizontal = "horizontal"; export var vertical = "vertical"; diff --git a/ui/styling/converters.ts b/ui/styling/converters.ts index e81928872..a74f806a8 100644 --- a/ui/styling/converters.ts +++ b/ui/styling/converters.ts @@ -24,6 +24,20 @@ export function textAlignConverter(value: string): string { } } +export function textDecorationConverter(value: string): string { + switch (value) { + case enums.TextDecoration.none: + case enums.TextDecoration.overline: + case enums.TextDecoration.underline: + case enums.TextDecoration.lineThrough: + return value; + break; + default: + throw new Error("CSS text-decoration \"" + value + "\" is not supported."); + break; + } +} + export var numberConverter = parseFloat; export function visibilityConverter(value: string): string { diff --git a/ui/styling/style.d.ts b/ui/styling/style.d.ts index 256cabe7e..a3790cbaf 100644 --- a/ui/styling/style.d.ts +++ b/ui/styling/style.d.ts @@ -44,6 +44,7 @@ declare module "ui/styling/style" { public fontWeight: string; public font: string; public textAlignment: string; + public textDecoration: string; public minWidth: number; public minHeight: number; public width: number; @@ -72,6 +73,7 @@ declare module "ui/styling/style" { public _inheritStyleProperty(property: Property): void; public _inheritStyleProperties(): void; public _boundsChanged(): void; + public _updateTextDecoration(): void; } export function registerHandler(property: Property, handler: styling.stylers.StylePropertyChangedHandler, className?: string); diff --git a/ui/styling/style.ts b/ui/styling/style.ts index 1ebe2aba2..a43984e1f 100644 --- a/ui/styling/style.ts +++ b/ui/styling/style.ts @@ -239,6 +239,10 @@ function isVisibilityValid(value: string): boolean { return value === enums.Visibility.visible || value === enums.Visibility.collapse || value === enums.Visibility.collapsed; } +function isTextDecorationValid(value: string): boolean { + return value === enums.TextDecoration.none || value === enums.TextDecoration.overline || value === enums.TextDecoration.underline || value === enums.TextDecoration.lineThrough; +} + function onVisibilityChanged(data: PropertyChangeData) { (data.object)._view._isVisibleCache = data.newValue === enums.Visibility.visible; } @@ -536,6 +540,19 @@ export class Style extends DependencyObservable implements styling.Style { this._setValue(opacityProperty, value); } + get textDecoration(): string { + return this._getValue(textDecorationProperty); + } + set textDecoration(value: string) { + this._setValue(textDecorationProperty, value); + } + + public _updateTextDecoration() { + if (this._getValue(textDecorationProperty) !== enums.TextDecoration.none) { + this._applyProperty(textDecorationProperty, this._getValue(textDecorationProperty)); + } + } + constructor(parentView: View) { super(); this._view = parentView; @@ -788,6 +805,9 @@ export var visibilityProperty = new styleProperty.Property("visibility", "visibi export var opacityProperty = new styleProperty.Property("opacity", "opacity", new PropertyMetadata(1.0, PropertyMetadataSettings.None, undefined, isOpacityValid), converters.opacityConverter); +export var textDecorationProperty = new styleProperty.Property("textDecoration", "text-decoration", + new PropertyMetadata(enums.TextDecoration.none, PropertyMetadataSettings.None, undefined, isTextDecorationValid), converters.textDecorationConverter); + // Helper property holding most layout related properties available in CSS. // When layout related properties are set in CSS we chache them and send them to the native view in a single call. export var nativeLayoutParamsProperty = new styleProperty.Property("nativeLayoutParams", "nativeLayoutParams", diff --git a/ui/styling/stylers.ios.ts b/ui/styling/stylers.ios.ts index 25e690d9e..205914e4b 100644 --- a/ui/styling/stylers.ios.ts +++ b/ui/styling/stylers.ios.ts @@ -7,6 +7,7 @@ import font = require("ui/styling/font"); import background = require("ui/styling/background"); import frame = require("ui/frame"); import tabView = require("ui/tab-view"); +import formattedString = require("text/formatted-string"); global.moduleMerge(stylersCommon, exports); @@ -14,6 +15,8 @@ interface TextUIView { font: UIFont; textAlignment: number; textColor: UIColor; + text : string; + attributedText : NSAttributedString; } var ignorePropertyHandler = new stylersCommon.StylePropertyChangedHandler( @@ -305,6 +308,15 @@ export class TextBaseStyler implements definition.stylers.Styler { return ios.textAlignment; } + // text-decoration + private static setTextDecorationProperty(view: view.View, newValue: any) { + setTextDecoration(view._nativeView, newValue); + } + + private static resetTextDecorationProperty(view: view.View, nativeValue: any) { + setTextDecoration(view._nativeView, enums.TextDecoration.none); + } + // color private static setColorProperty(view: view.View, newValue: any) { var ios: TextUIView = view._nativeView; @@ -336,6 +348,10 @@ export class TextBaseStyler implements definition.stylers.Styler { TextBaseStyler.setColorProperty, TextBaseStyler.resetColorProperty, TextBaseStyler.getNativeColorValue), "TextBase"); + + style.registerHandler(style.textDecorationProperty, new stylersCommon.StylePropertyChangedHandler( + TextBaseStyler.setTextDecorationProperty, + TextBaseStyler.resetTextDecorationProperty), "TextBase"); } } @@ -880,6 +896,36 @@ function setTextAlignment(view: TextUIView, value: string) { } } +function setTextDecoration(view: TextUIView, value: string) { + switch (value) { + case enums.TextDecoration.none: + + break; + case enums.TextDecoration.overline: + + break; + case enums.TextDecoration.underline: + setTextDecorationNative(view, view.text || view.attributedText, NSUnderlineStyleAttributeName); + break; + case enums.TextDecoration.lineThrough: + setTextDecorationNative(view, view.text || view.attributedText, NSStrikethroughStyleAttributeName); + break; + default: + break; + } +} + +function setTextDecorationNative(view: TextUIView, value: string | NSAttributedString, attribute: string) { + var attributedString: NSMutableAttributedString; + + if (value instanceof NSAttributedString) { + attributedString = NSMutableAttributedString.alloc().initWithAttributedString(value); + attributedString.addAttributesRange({ [attribute]: NSUnderlineStyle.NSUnderlineStyleSingle }, NSRangeFromString(attributedString.string)); + } else { + view.attributedText = NSAttributedString.alloc().initWithStringAttributes(value, { [attribute]: NSUnderlineStyle.NSUnderlineStyleSingle }); + } +} + // Register all styler at the end. export function _registerDefaultStylers() { style.registerNoStylingClass("Frame"); diff --git a/ui/styling/styling.d.ts b/ui/styling/styling.d.ts index ede2671a4..033854dc2 100644 --- a/ui/styling/styling.d.ts +++ b/ui/styling/styling.d.ts @@ -205,6 +205,7 @@ public _syncNativeProperties(): void; public _inheritStyleProperty(property: dependencyObservable.Property): void; public _inheritStyleProperties(): void; + public _updateTextDecoration(): void; //@endprivate } diff --git a/ui/text-base/text-base.ts b/ui/text-base/text-base.ts index 028016406..ad6a06971 100644 --- a/ui/text-base/text-base.ts +++ b/ui/text-base/text-base.ts @@ -95,6 +95,7 @@ export class TextBase extends view.View implements definition.TextBase, formatte } else if (this.ios) { this.ios.text = data.newValue + ""; + this.style._updateTextDecoration(); } } @@ -103,6 +104,7 @@ export class TextBase extends view.View implements definition.TextBase, formatte this.android.setText(value._formattedText); } else if (this.ios) { this.ios.attributedText = value._formattedText; + this.style._updateTextDecoration(); this.requestLayout(); } } diff --git a/ui/text-field/text-field.ios.ts b/ui/text-field/text-field.ios.ts index d23839e4e..cea7093b7 100644 --- a/ui/text-field/text-field.ios.ts +++ b/ui/text-field/text-field.ios.ts @@ -69,6 +69,9 @@ class UITextFieldDelegateImpl extends NSObject implements UITextFieldDelegate { public textFieldShouldChangeCharactersInRangeReplacementString(textField: UITextField, range: NSRange, replacementString: string): boolean { let owner = this._owner.get(); if (owner) { + + owner.style._updateTextDecoration(); + if (owner.updateTextTrigger === enums.UpdateTextTrigger.textChanged) { if (textField.secureTextEntry && this.firstEdit) { owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, replacementString); diff --git a/ui/text-view/text-view.ios.ts b/ui/text-view/text-view.ios.ts index 700c2dd49..bfa20245a 100644 --- a/ui/text-view/text-view.ios.ts +++ b/ui/text-view/text-view.ios.ts @@ -20,11 +20,13 @@ class UITextViewDelegateImpl extends NSObject implements UITextViewDelegate { } public textViewShouldBeginEditing(textView: UITextView): boolean { + this._owner.style._updateTextDecoration(); this._owner._hideHint(); return true; } public textViewDidEndEditing(textView: UITextView) { + this._owner.style._updateTextDecoration(); if (this._owner.updateTextTrigger === enums.UpdateTextTrigger.focusLost) { this._owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, textView.text); } @@ -34,6 +36,8 @@ class UITextViewDelegateImpl extends NSObject implements UITextViewDelegate { } public textViewDidChange(textView: UITextView) { + this._owner.style._updateTextDecoration(); + if (this._owner.updateTextTrigger === enums.UpdateTextTrigger.textChanged) { this._owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, textView.text); } From 4cdfb6405195e850420ad683f84272445ba61d40 Mon Sep 17 00:00:00 2001 From: Vladimir Enchev Date: Fri, 6 Nov 2015 11:20:38 +0200 Subject: [PATCH 02/15] range fixed --- ui/text-field/text-field.ios.ts | 2 ++ ui/text-view/text-view.ios.ts | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ui/text-field/text-field.ios.ts b/ui/text-field/text-field.ios.ts index cea7093b7..494a80b76 100644 --- a/ui/text-field/text-field.ios.ts +++ b/ui/text-field/text-field.ios.ts @@ -70,7 +70,9 @@ class UITextFieldDelegateImpl extends NSObject implements UITextFieldDelegate { let owner = this._owner.get(); if (owner) { + var r = textField.selectedTextRange; owner.style._updateTextDecoration(); + textField.selectedTextRange = r; if (owner.updateTextTrigger === enums.UpdateTextTrigger.textChanged) { if (textField.secureTextEntry && this.firstEdit) { diff --git a/ui/text-view/text-view.ios.ts b/ui/text-view/text-view.ios.ts index bfa20245a..bd1fff0af 100644 --- a/ui/text-view/text-view.ios.ts +++ b/ui/text-view/text-view.ios.ts @@ -20,13 +20,15 @@ class UITextViewDelegateImpl extends NSObject implements UITextViewDelegate { } public textViewShouldBeginEditing(textView: UITextView): boolean { - this._owner.style._updateTextDecoration(); this._owner._hideHint(); return true; } - public textViewDidEndEditing(textView: UITextView) { + public textViewDidBeginEditing(textView: UITextView) { this._owner.style._updateTextDecoration(); + } + + public textViewDidEndEditing(textView: UITextView) { if (this._owner.updateTextTrigger === enums.UpdateTextTrigger.focusLost) { this._owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, textView.text); } @@ -36,7 +38,9 @@ class UITextViewDelegateImpl extends NSObject implements UITextViewDelegate { } public textViewDidChange(textView: UITextView) { + var range = textView.selectedRange; this._owner.style._updateTextDecoration(); + textView.selectedRange = range; if (this._owner.updateTextTrigger === enums.UpdateTextTrigger.textChanged) { this._owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, textView.text); From bc68f1eabb224e6adb5e12a5c470f7e78c4f758d Mon Sep 17 00:00:00 2001 From: Vladimir Enchev Date: Fri, 6 Nov 2015 11:44:01 +0200 Subject: [PATCH 03/15] overline removed --- ui/enums/enums.d.ts | 6 ------ ui/enums/enums.ts | 3 +-- ui/styling/converters.ts | 1 - ui/styling/style.ts | 2 +- ui/styling/stylers.ios.ts | 5 +---- 5 files changed, 3 insertions(+), 14 deletions(-) diff --git a/ui/enums/enums.d.ts b/ui/enums/enums.d.ts index 2eada7b88..955ba74cd 100644 --- a/ui/enums/enums.d.ts +++ b/ui/enums/enums.d.ts @@ -432,18 +432,12 @@ */ export var underline: string; - /** - * Text decoration overline. - */ - export var overline: string; - /** * Text decoration line-through. */ export var lineThrough: string; } - /** * Specifies different font weights. */ diff --git a/ui/enums/enums.ts b/ui/enums/enums.ts index 3b2a409a0..9d0618625 100644 --- a/ui/enums/enums.ts +++ b/ui/enums/enums.ts @@ -23,8 +23,7 @@ export module TextAlignment { export module TextDecoration { export var none = "none"; export var underline = "underline"; - export var overline = "overline"; - export var lineThrough = "lineThrough"; + export var lineThrough = "line-through"; } export module Orientation { diff --git a/ui/styling/converters.ts b/ui/styling/converters.ts index a74f806a8..40f23be64 100644 --- a/ui/styling/converters.ts +++ b/ui/styling/converters.ts @@ -27,7 +27,6 @@ export function textAlignConverter(value: string): string { export function textDecorationConverter(value: string): string { switch (value) { case enums.TextDecoration.none: - case enums.TextDecoration.overline: case enums.TextDecoration.underline: case enums.TextDecoration.lineThrough: return value; diff --git a/ui/styling/style.ts b/ui/styling/style.ts index a43984e1f..9a3b936bc 100644 --- a/ui/styling/style.ts +++ b/ui/styling/style.ts @@ -240,7 +240,7 @@ function isVisibilityValid(value: string): boolean { } function isTextDecorationValid(value: string): boolean { - return value === enums.TextDecoration.none || value === enums.TextDecoration.overline || value === enums.TextDecoration.underline || value === enums.TextDecoration.lineThrough; + return value === enums.TextDecoration.none || value === enums.TextDecoration.underline || value === enums.TextDecoration.lineThrough; } function onVisibilityChanged(data: PropertyChangeData) { diff --git a/ui/styling/stylers.ios.ts b/ui/styling/stylers.ios.ts index 205914e4b..b0f44a518 100644 --- a/ui/styling/stylers.ios.ts +++ b/ui/styling/stylers.ios.ts @@ -899,10 +899,7 @@ function setTextAlignment(view: TextUIView, value: string) { function setTextDecoration(view: TextUIView, value: string) { switch (value) { case enums.TextDecoration.none: - - break; - case enums.TextDecoration.overline: - + view.text = view.attributedText ? view.attributedText.string : view.text; break; case enums.TextDecoration.underline: setTextDecorationNative(view, view.text || view.attributedText, NSUnderlineStyleAttributeName); From 28bafb6cd5eb7791e644fb206649ad01b13f1011 Mon Sep 17 00:00:00 2001 From: Vladimir Enchev Date: Fri, 6 Nov 2015 13:08:28 +0200 Subject: [PATCH 04/15] TextDecoration for android added --- ui/styling/stylers.android.ts | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/ui/styling/stylers.android.ts b/ui/styling/stylers.android.ts index 13676682c..13e62cbf7 100644 --- a/ui/styling/stylers.android.ts +++ b/ui/styling/stylers.android.ts @@ -416,6 +416,15 @@ export class TextViewStyler implements definition.stylers.Styler { return view._nativeView.getGravity(); } + // text-decoration + private static setTextDecorationProperty(view: view.View, newValue: any) { + setTextDecoration(view._nativeView, newValue); + } + + private static resetTextDecorationProperty(view: view.View, nativeValue: any) { + setTextDecoration(view._nativeView, enums.TextDecoration.none); + } + public static registerHandlers() { style.registerHandler(style.colorProperty, new stylersCommon.StylePropertyChangedHandler( TextViewStyler.setColorProperty, @@ -432,6 +441,10 @@ export class TextViewStyler implements definition.stylers.Styler { TextViewStyler.resetTextAlignmentProperty, TextViewStyler.getNativeTextAlignmentValue), "TextBase"); + style.registerHandler(style.textDecorationProperty, new stylersCommon.StylePropertyChangedHandler( + TextViewStyler.setTextDecorationProperty, + TextViewStyler.resetTextDecorationProperty), "TextBase"); + // Register the same stylers for Button. // It also derives from TextView but is not under TextBase in our View hierarchy. style.registerHandler(style.colorProperty, new stylersCommon.StylePropertyChangedHandler( @@ -448,6 +461,26 @@ export class TextViewStyler implements definition.stylers.Styler { TextViewStyler.setTextAlignmentProperty, TextViewStyler.resetTextAlignmentProperty, TextViewStyler.getNativeTextAlignmentValue), "Button"); + + style.registerHandler(style.textDecorationProperty, new stylersCommon.StylePropertyChangedHandler( + TextViewStyler.setTextDecorationProperty, + TextViewStyler.resetTextDecorationProperty), "Button"); + } +} + +function setTextDecoration(view: android.widget.TextView, value: string) { + switch (value) { + case enums.TextDecoration.none: + view.setPaintFlags(view.getPaintFlags()); + break; + case enums.TextDecoration.underline: + view.setPaintFlags(view.getPaintFlags() | android.graphics.Paint.UNDERLINE_TEXT_FLAG); + break; + case enums.TextDecoration.lineThrough: + view.setPaintFlags(view.getPaintFlags() | android.graphics.Paint.STRIKE_THRU_TEXT_FLAG); + break; + default: + break; } } @@ -823,7 +856,7 @@ export class ActionBarStyler implements definition.stylers.Styler { private static setColorProperty(view: view.View, newValue: any) { var toolbar = (view._nativeView); toolbar.setTitleTextColor(newValue); - + } private static resetColorProperty(view: view.View, nativeValue: any) { From f2db20c694482abcbafab27d6c1e77cbab768891 Mon Sep 17 00:00:00 2001 From: Vladimir Enchev Date: Fri, 6 Nov 2015 13:16:10 +0200 Subject: [PATCH 05/15] TextDecoration added to buttons for iOS --- ui/styling/stylers.ios.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ui/styling/stylers.ios.ts b/ui/styling/stylers.ios.ts index b0f44a518..c1947969d 100644 --- a/ui/styling/stylers.ios.ts +++ b/ui/styling/stylers.ios.ts @@ -254,6 +254,15 @@ export class ButtonStyler implements definition.stylers.Styler { (view._nativeView).contentEdgeInsets = UIEdgeInsetsFromString("{0,0,0,0}"); } + // text-decoration + private static setTextDecorationProperty(view: view.View, newValue: any) { + setTextDecoration((view.ios).titleLabel, newValue); + } + + private static resetTextDecorationProperty(view: view.View, nativeValue: any) { + setTextDecoration((view.ios).titleLabel, enums.TextDecoration.none); + } + public static registerHandlers() { style.registerHandler(style.colorProperty, new stylersCommon.StylePropertyChangedHandler( ButtonStyler.setColorProperty, @@ -273,6 +282,10 @@ export class ButtonStyler implements definition.stylers.Styler { style.registerHandler(style.nativePaddingsProperty, new stylersCommon.StylePropertyChangedHandler( ButtonStyler.setPaddingProperty, ButtonStyler.resetPaddingProperty), "Button"); + + style.registerHandler(style.textDecorationProperty, new stylersCommon.StylePropertyChangedHandler( + ButtonStyler.setTextDecorationProperty, + ButtonStyler.resetTextDecorationProperty), "Button"); } } From 2432cf9d4d7dad63253a24c271c9655f8daf344f Mon Sep 17 00:00:00 2001 From: Vladimir Enchev Date: Fri, 6 Nov 2015 13:26:05 +0200 Subject: [PATCH 06/15] test page added --- apps/gallery-app/app.css | 3 ++- apps/gallery-app/text-decoration.xml | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 apps/gallery-app/text-decoration.xml diff --git a/apps/gallery-app/app.css b/apps/gallery-app/app.css index 569d88605..42bbc7c77 100644 --- a/apps/gallery-app/app.css +++ b/apps/gallery-app/app.css @@ -21,6 +21,7 @@ Switch, Progress, Slider, SegmentedBar { background-color: aquamarine; }*/ +/* TextView, TextField, Label, Button { text-decoration: underline; -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/apps/gallery-app/text-decoration.xml b/apps/gallery-app/text-decoration.xml new file mode 100644 index 000000000..82f6e9f56 --- /dev/null +++ b/apps/gallery-app/text-decoration.xml @@ -0,0 +1,16 @@ + + +