diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj
index 3cfa4b18a..31dde677d 100644
--- a/CrossPlatformModules.csproj
+++ b/CrossPlatformModules.csproj
@@ -238,6 +238,7 @@
color.xml
+
html-view.xml
diff --git a/apps/gallery-app/app.css b/apps/gallery-app/app.css
index 0dc6af8bc..42bbc7c77 100644
--- a/apps/gallery-app/app.css
+++ b/apps/gallery-app/app.css
@@ -19,4 +19,9 @@ ActionBar, TabView, ActivityIndicator, Label, Button, TextView, TextField, Searc
Switch, Progress, Slider, SegmentedBar {
color: mediumaquamarine;
background-color: aquamarine;
+}*/
+
+/*
+TextView, TextField, Label, Button {
+ text-decoration: underline;
}*/
\ No newline at end of file
diff --git a/apps/ui-tests-app/css/text-decoration.ts b/apps/ui-tests-app/css/text-decoration.ts
new file mode 100644
index 000000000..eceb2f30e
--- /dev/null
+++ b/apps/ui-tests-app/css/text-decoration.ts
@@ -0,0 +1,17 @@
+var obj;
+
+export function loaded(args) {
+ obj = args.object;
+}
+
+export function butonTap(args) {
+ if (obj.style.textDecoration === "underline") {
+ obj.style.textDecoration = "line-through";
+ } else if (obj.style.textDecoration === "line-through") {
+ obj.style.textDecoration = "line-through underline";
+ } else if (obj.style.textDecoration === "line-through underline") {
+ obj.style.textDecoration = "none";
+ } else if (obj.style.textDecoration === "none") {
+ obj.style.textDecoration = "underline";
+ }
+}
\ No newline at end of file
diff --git a/apps/ui-tests-app/css/text-decoration.xml b/apps/ui-tests-app/css/text-decoration.xml
new file mode 100644
index 000000000..f1a99cadb
--- /dev/null
+++ b/apps/ui-tests-app/css/text-decoration.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/ui-tests-app/mainPage.ts b/apps/ui-tests-app/mainPage.ts
index cf9ceac8a..ded293282 100644
--- a/apps/ui-tests-app/mainPage.ts
+++ b/apps/ui-tests-app/mainPage.ts
@@ -90,4 +90,5 @@ examples.set("textfield", "text-field/text-field");
examples.set("webview", "web-view/web-view");
examples.set("webtest", "web-view/web-vew-test");
+examples.set("decoration", "css/text-decoration");
//VM.set("selected", "tabAll");
\ No newline at end of file
diff --git a/ui/enums/enums.d.ts b/ui/enums/enums.d.ts
index 997b6c8b6..955ba74cd 100644
--- a/ui/enums/enums.d.ts
+++ b/ui/enums/enums.d.ts
@@ -417,7 +417,26 @@
*/
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 line-through.
+ */
+ export var lineThrough: string;
+ }
/**
* Specifies different font weights.
diff --git a/ui/enums/enums.ts b/ui/enums/enums.ts
index f5b98857a..9d0618625 100644
--- a/ui/enums/enums.ts
+++ b/ui/enums/enums.ts
@@ -20,6 +20,12 @@ export module TextAlignment {
export var right = "right";
}
+export module TextDecoration {
+ export var none = "none";
+ export var underline = "underline";
+ export var lineThrough = "line-through";
+}
+
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..7b4eb4cb2 100644
--- a/ui/styling/converters.ts
+++ b/ui/styling/converters.ts
@@ -17,10 +17,18 @@ export function textAlignConverter(value: string): string {
case enums.TextAlignment.center:
case enums.TextAlignment.right:
return value;
- break;
default:
throw new Error("CSS text-align \"" + value + "\" is not supported.");
- break;
+ }
+}
+
+export function textDecorationConverter(value: string): string {
+ var values = (value + "").split(" ");
+
+ if (values.indexOf(enums.TextDecoration.none) !== -1 || values.indexOf(enums.TextDecoration.underline) !== -1 || values.indexOf(enums.TextDecoration.lineThrough) !== -1) {
+ return value;
+ } else {
+ throw new Error("CSS text-decoration \"" + value + "\" is not supported.");
}
}
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..1513d3b87 100644
--- a/ui/styling/style.ts
+++ b/ui/styling/style.ts
@@ -239,6 +239,12 @@ function isVisibilityValid(value: string): boolean {
return value === enums.Visibility.visible || value === enums.Visibility.collapse || value === enums.Visibility.collapsed;
}
+function isTextDecorationValid(value: string): boolean {
+ var values = (value + "").split(" ");
+
+ return values.indexOf(enums.TextDecoration.none) !== -1 || values.indexOf(enums.TextDecoration.underline) !== -1 || values.indexOf(enums.TextDecoration.lineThrough) !== -1;
+}
+
function onVisibilityChanged(data: PropertyChangeData) {
(data.object)._view._isVisibleCache = data.newValue === enums.Visibility.visible;
}
@@ -536,6 +542,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 +807,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.android.ts b/ui/styling/stylers.android.ts
index 13676682c..94c5881ee 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,9 +461,33 @@ 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) {
+ var flags = 0;
+
+ var values = (value + "").split(" ");
+
+ if (values.indexOf(enums.TextDecoration.underline) !== -1) {
+ flags = flags | android.graphics.Paint.UNDERLINE_TEXT_FLAG;
+ }
+
+ if (values.indexOf(enums.TextDecoration.lineThrough) !== -1) {
+ flags = flags | android.graphics.Paint.STRIKE_THRU_TEXT_FLAG;
+ }
+
+ if (values.indexOf(enums.TextDecoration.none) === -1) {
+ view.setPaintFlags(flags);
+ } else {
+ view.setPaintFlags(0);
+ }
+}
+
export class ActivityIndicatorStyler implements definition.stylers.Styler {
private static setColorProperty(view: view.View, newValue: any) {
var bar = view._nativeView;
@@ -823,7 +860,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) {
diff --git a/ui/styling/stylers.ios.ts b/ui/styling/stylers.ios.ts
index 25e690d9e..0e2950c5b 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(
@@ -251,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,
@@ -270,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");
}
}
@@ -305,6 +321,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 +361,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 +909,36 @@ function setTextAlignment(view: TextUIView, value: string) {
}
}
+function setTextDecoration(view: TextUIView, value: string) {
+ var attributes: NSMutableDictionary = NSMutableDictionary.alloc().init();
+ var values = (value + "").split(" ");
+
+ if (values.indexOf(enums.TextDecoration.underline) !== -1) {
+ attributes.setObjectForKey(NSUnderlineStyle.NSUnderlineStyleSingle, NSUnderlineStyleAttributeName);
+ }
+
+ if (values.indexOf(enums.TextDecoration.lineThrough) !== -1) {
+ attributes.setObjectForKey(NSUnderlineStyle.NSUnderlineStyleSingle, NSStrikethroughStyleAttributeName);
+ }
+
+ if (values.indexOf(enums.TextDecoration.none) === -1) {
+ setTextDecorationNative(view, view.text || view.attributedText, attributes);
+ } else {
+ setTextDecorationNative(view, view.text || view.attributedText, NSMutableDictionary.alloc().init());
+ }
+}
+
+function setTextDecorationNative(view: TextUIView, value: string | NSAttributedString, attributes: NSMutableDictionary) {
+ var attributedString: NSMutableAttributedString;
+
+ if (value instanceof NSAttributedString) {
+ attributedString = NSMutableAttributedString.alloc().initWithAttributedString(value);
+ attributedString.addAttributesRange(attributes, NSRangeFromString(attributedString.string));
+ } else {
+ view.attributedText = NSAttributedString.alloc().initWithStringAttributes(value, attributes);
+ }
+}
+
// 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..494a80b76 100644
--- a/ui/text-field/text-field.ios.ts
+++ b/ui/text-field/text-field.ios.ts
@@ -69,6 +69,11 @@ class UITextFieldDelegateImpl extends NSObject implements UITextFieldDelegate {
public textFieldShouldChangeCharactersInRangeReplacementString(textField: UITextField, range: NSRange, replacementString: string): boolean {
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) {
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..bd1fff0af 100644
--- a/ui/text-view/text-view.ios.ts
+++ b/ui/text-view/text-view.ios.ts
@@ -24,6 +24,10 @@ class UITextViewDelegateImpl extends NSObject implements UITextViewDelegate {
return true;
}
+ 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);
@@ -34,6 +38,10 @@ 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);
}