From 57312ef1f3a93092ec89b4a36092bbbd50c7b045 Mon Sep 17 00:00:00 2001 From: Vladimir Enchev Date: Tue, 14 Jul 2015 14:48:41 +0300 Subject: [PATCH 1/4] initial commit --- CrossPlatformModules.csproj | 11 +++-- ui/html-view/html-view-common.ts | 23 +++++++++ ui/html-view/html-view.android.ts | 34 +++++++++++++ ui/html-view/html-view.d.ts | 45 +++++++++++++++++ ui/html-view/html-view.ios.ts | 82 +++++++++++++++++++++++++++++++ ui/html-view/package.json | 2 + 6 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 ui/html-view/html-view-common.ts create mode 100644 ui/html-view/html-view.android.ts create mode 100644 ui/html-view/html-view.d.ts create mode 100644 ui/html-view/html-view.ios.ts create mode 100644 ui/html-view/package.json diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj index 7d201e7d8..0b69d73f5 100644 --- a/CrossPlatformModules.csproj +++ b/CrossPlatformModules.csproj @@ -277,7 +277,7 @@ - webview.xml + webview.xml @@ -436,6 +436,10 @@ action-bar.d.ts + + + + repeater.d.ts @@ -797,7 +801,7 @@ - + PreserveNewest @@ -1683,6 +1687,7 @@ + PreserveNewest @@ -1747,7 +1752,7 @@ False - + \ No newline at end of file diff --git a/ui/html-view/html-view-common.ts b/ui/html-view/html-view-common.ts new file mode 100644 index 000000000..d6ad1a000 --- /dev/null +++ b/ui/html-view/html-view-common.ts @@ -0,0 +1,23 @@ +import definition = require("ui/html-view"); +import dependencyObservable = require("ui/core/dependency-observable"); +import proxy = require("ui/core/proxy"); +import view = require("ui/core/view"); + +export class HtmlView extends view.View implements definition.HtmlView { + public static htmlProperty = new dependencyObservable.Property( + "html", + "HtmlView", + new proxy.PropertyMetadata(false, dependencyObservable.PropertyMetadataSettings.AffectsLayout) + ); + + constructor(options?: definition.Options) { + super(options); + } + + get html(): string { + return this._getValue(HtmlView.htmlProperty); + } + set html(value: string) { + this._setValue(HtmlView.htmlProperty, value); + } +} \ No newline at end of file diff --git a/ui/html-view/html-view.android.ts b/ui/html-view/html-view.android.ts new file mode 100644 index 000000000..0933a041a --- /dev/null +++ b/ui/html-view/html-view.android.ts @@ -0,0 +1,34 @@ +import common = require("ui/html-view/html-view-common"); +import dependencyObservable = require("ui/core/dependency-observable"); +import proxy = require("ui/core/proxy"); +import types = require("utils/types"); + +function onHtmlPropertyChanged(data: dependencyObservable.PropertyChangeData) { + var view = data.object; + if (!view.android) { + return; + } + + if (types.isString(data.newValue)) { + view.android.setText(android.text.Html.fromHtml(data.newValue)); + } +} + +// register the setNativeValue callback +(common.HtmlView.htmlProperty.metadata).onSetNativeValue = onHtmlPropertyChanged; + +// merge the exports of the common file with the exports of this file +declare var exports; +require("utils/module-merge").merge(common, exports); + +export class HtmlView extends common.HtmlView { + private _android: android.widget.TextView; + + get android(): android.widget.TextView { + return this._android; + } + + public _createUI() { + this._android = new android.widget.TextView(this._context); + } +} \ No newline at end of file diff --git a/ui/html-view/html-view.d.ts b/ui/html-view/html-view.d.ts new file mode 100644 index 000000000..f44eb7328 --- /dev/null +++ b/ui/html-view/html-view.d.ts @@ -0,0 +1,45 @@ +/** + * Contains the HtmlView class, which represents a standard html view widget. + */ +declare module "ui/html-view" { + import view = require("ui/core/view"); + import dependencyObservable = require("ui/core/dependency-observable"); + + /** + * Represents a view with html content. + */ + export class HtmlView extends view.View { + + /** + * Dependency property used to support binding operations for the html of the current HtmlView instance. + */ + public static htmlProperty: dependencyObservable.Property; + + constructor(options?: Options); + + /** + * Gets the native [android widget](http://developer.android.com/reference/android/widget/TextView.html) that represents the user interface for this component. Valid only when running on Android OS. + */ + android: android.widget.TextView; + + /** + * Gets the native [UILabel](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UILabel_Class/) that represents the user interface for this component. Valid only when running on iOS. + */ + ios: UILabel; + + /** + * Gets or sets html string for the HtmlView. + */ + html: string; + } + + /** + * Provides a set of most common options for creating a HtmlView. + */ + export interface Options extends view.Options { + /** + * Gets or sets the html content of a HtmlView. + */ + html?: string; + } +} \ No newline at end of file diff --git a/ui/html-view/html-view.ios.ts b/ui/html-view/html-view.ios.ts new file mode 100644 index 000000000..68aba2ccd --- /dev/null +++ b/ui/html-view/html-view.ios.ts @@ -0,0 +1,82 @@ +import common = require("ui/html-view/html-view-common"); +import definition = require("ui/html-view"); +import dependencyObservable = require("ui/core/dependency-observable"); +import proxy = require("ui/core/proxy"); +import utils = require("utils/utils"); +import types = require("utils/types"); +import viewModule = require("ui/core/view"); + +function onHtmlPropertyChanged(data: dependencyObservable.PropertyChangeData) { + var view = data.object; + if (!view.android) { + return; + } + + if (types.isString(data.newValue)) { + var htmlString = NSString.stringWithString(data.newValue); + var nsData = htmlString.dataUsingEncoding(NSUnicodeStringEncoding); + var options = NSDictionary.new(); + options.setValueForKey(NSDocumentTypeDocumentAttribute, NSHTMLTextDocumentType); + view.ios.attributedText = NSAttributedString.alloc().initWithDataOptionsDocumentAttributesError(nsData, options, null); + } +} + +// register the setNativeValue callback +(common.HtmlView.htmlProperty.metadata).onSetNativeValue = onHtmlPropertyChanged; + +// merge the exports of the common file with the exports of this file +declare var exports; +require("utils/module-merge").merge(common, exports); + +export class HtmlView extends common.HtmlView { + private _ios: UILabel; + + constructor(options?: definition.Options) { + super(options); + + this._ios = new UILabel(); + super._prepareNativeView(this._ios); + } + + get ios(): UILabel { + return this._ios; + } + + get _nativeView(): UILabel { + return this._ios; + } + + public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void { + var nativeView = this._nativeView; + if (nativeView) { + + var width = utils.layout.getMeasureSpecSize(widthMeasureSpec); + var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec); + + var height = utils.layout.getMeasureSpecSize(heightMeasureSpec); + var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec); + + if (widthMode === utils.layout.UNSPECIFIED) { + width = Number.POSITIVE_INFINITY; + } + + if (heightMode === utils.layout.UNSPECIFIED) { + height = Number.POSITIVE_INFINITY; + } + + var nativeSize = nativeView.sizeThatFits(CGSizeMake(width, height)); + var labelWidth = nativeSize.width; + //if (!this.textWrap) { + labelWidth = Math.min(labelWidth, width); + //} + + var measureWidth = Math.max(labelWidth, this.minWidth); + var measureHeight = Math.max(nativeSize.height, this.minHeight); + + var widthAndState = viewModule.View.resolveSizeAndState(measureWidth, width, widthMode, 0); + var heightAndState = viewModule.View.resolveSizeAndState(measureHeight, height, heightMode, 0); + + this.setMeasuredDimension(widthAndState, heightAndState); + } + } +} \ No newline at end of file diff --git a/ui/html-view/package.json b/ui/html-view/package.json new file mode 100644 index 000000000..69b5ab220 --- /dev/null +++ b/ui/html-view/package.json @@ -0,0 +1,2 @@ +{ "name" : "html-view", + "main" : "html-view.js" } \ No newline at end of file From 835ab8c142f55eb61fb23539effc53a68131586f Mon Sep 17 00:00:00 2001 From: Vladimir Enchev Date: Wed, 15 Jul 2015 11:59:00 +0300 Subject: [PATCH 2/4] HtmlView UI component added + test --- CrossPlatformModules.csproj | 3 +- apps/tests/testRunner.ts | 1 + apps/tests/ui/html-view/html-view-tests.ts | 56 ++++++++++++++++++++++ apps/tests/xml-declaration/mainPage.xml | 2 + ui/builder/component-builder.ts | 1 + ui/html-view/html-view.android.ts | 2 + ui/html-view/html-view.d.ts | 4 +- ui/html-view/html-view.ios.ts | 13 +++-- 8 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 apps/tests/ui/html-view/html-view-tests.ts diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj index 0b69d73f5..c9d81265f 100644 --- a/CrossPlatformModules.csproj +++ b/CrossPlatformModules.csproj @@ -236,6 +236,7 @@ + @@ -1752,7 +1753,7 @@ False - + \ No newline at end of file diff --git a/apps/tests/testRunner.ts b/apps/tests/testRunner.ts index a39c70c74..ce0f61ebc 100644 --- a/apps/tests/testRunner.ts +++ b/apps/tests/testRunner.ts @@ -70,6 +70,7 @@ allTests["LIST-PICKER"] = require("./ui/list-picker/list-picker-tests"); allTests["DATE-PICKER"] = require("./ui/date-picker/date-picker-tests"); allTests["TIME-PICKER"] = require("./ui/time-picker/time-picker-tests"); allTests["WEB-VIEW"] = require("./ui/web-view/web-view-tests"); +allTests["HTML-VIEW"] = require("./ui/html-view/html-view-tests"); allTests["WEAK-EVENTS"] = require("./weak-event-listener-tests"); allTests["REPEATER"] = require("./ui/repeater/repeater-tests"); allTests["SEARCH-BAR"] = require('./ui/search-bar/search-bar-tests'); diff --git a/apps/tests/ui/html-view/html-view-tests.ts b/apps/tests/ui/html-view/html-view-tests.ts new file mode 100644 index 000000000..04c519ac0 --- /dev/null +++ b/apps/tests/ui/html-view/html-view-tests.ts @@ -0,0 +1,56 @@ +import TKUnit = require("../../TKUnit"); +import helper = require("../helper"); +import page = require("ui/page"); +import types = require("utils/types"); + +// +// # WebView +// Using a HtmlView requires the html-view module. +// ``` JavaScript +import htmlViewModule = require("ui/html-view"); +// ``` +// + +// ### Declaring a HtmlView. +//```XML +// +// +// +//``` + +//  + +var _createHtmlViewFunc = function (): htmlViewModule.HtmlView { + // + // ### Creating a HtmlView + // ``` JavaScript + var htmlView = new htmlViewModule.HtmlView(); + // ``` + // + return htmlView; +} + +export var testLoadHTMLString = function () { + var newPage: page.Page; + var htmlView = _createHtmlViewFunc(); + var pageFactory = function (): page.Page { + newPage = new page.Page(); + newPage.content = htmlView; + return newPage; + }; + + helper.navigate(pageFactory); + + // + // ### Using HtmlView + // ``` JavaScript + htmlView.html = 'Test'; + + helper.goBack(); + + if (htmlView.ios) { + TKUnit.assert(!types.isNullOrUndefined(htmlView.ios.attributedText), "HTML string not loaded properly. Actual: " + htmlView.ios.attributedText); + } else if (htmlView.android) { + TKUnit.assert(htmlView.android.getText(), "HTML string not loaded properly. Actual: " + htmlView.android.getText()); + } +} \ No newline at end of file diff --git a/apps/tests/xml-declaration/mainPage.xml b/apps/tests/xml-declaration/mainPage.xml index d801544c8..46321e44d 100644 --- a/apps/tests/xml-declaration/mainPage.xml +++ b/apps/tests/xml-declaration/mainPage.xml @@ -7,6 +7,8 @@ + +