Merge pull request #179 from NativeScript/webview-src

Implemented #172.
This commit is contained in:
Vladimir Enchev
2015-05-19 14:26:46 +03:00
11 changed files with 257 additions and 18 deletions

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>MyTitle</title>
<meta charset="utf-8" />
</head>
<body>
<span style="color:red">Test</span>
</body>
</html>

View File

@ -13,9 +13,10 @@ import webViewModule = require("ui/web-view");
// ### Declaring a WebView.
//```XML
// <Page>
// <WebView url="{{ someUrl }}" />
// <WebView src="{{ someUrl | pathToLocalFile | htmlString }}" />
// </Page>
//```
// </snippet>
var _createWebViewFunc = function (): webViewModule.WebView {
@ -76,6 +77,128 @@ export var testLoadExistingUrl = function () {
}
}
export var testLoadLocalFile = function () {
var newPage: page.Page;
var webView = _createWebViewFunc();
var pageFactory = function (): page.Page {
newPage = new page.Page();
newPage.content = webView;
return newPage;
};
helper.navigate(pageFactory);
var testFinished = false;
var actualHtml;
var actualTitle;
var actualError;
var expectedTitle = 'MyTitle';
var expectedHtml = '<span style="color:red">Test</span>';
// <snippet module="ui/web-view" title="WebView">
// ### Using WebView
// ``` JavaScript
webView.on(webViewModule.WebView.loadFinishedEvent, function (args: webViewModule.LoadEventData) {
// <hide>
if (webView.ios) {
actualHtml = webView.ios.stringByEvaluatingJavaScriptFromString("document.body.innerHTML").trim();
} else if (webView.android) {
actualTitle = webView.android.getTitle()
}
actualError = args.error;
testFinished = true;
// </hide>
var message;
if (!args.error) {
message = "WebView finished loading " + args.url;
}
else {
message = "Error loading " + args.url + ": " + args.error;
}
//console.log(message);
});
webView.src = "~/ui/web-view/test.html";
TKUnit.wait(4);
helper.goBack();
if (testFinished) {
if (webView.ios) {
TKUnit.assert(actualHtml === expectedHtml, "File ~/ui/web-view/test.html not loaded properly. Actual: " + actualHtml);
} else if (webView.android) {
TKUnit.assert(actualTitle === expectedTitle, "File ~/ui/web-view/test.html not loaded properly. Actual: " + actualTitle);
}
TKUnit.assert(actualError === undefined, actualError);
}
else {
TKUnit.assert(false, "TIMEOUT");
}
}
export var testLoadHTMLString = function () {
var newPage: page.Page;
var webView = _createWebViewFunc();
var pageFactory = function (): page.Page {
newPage = new page.Page();
newPage.content = webView;
return newPage;
};
helper.navigate(pageFactory);
var testFinished = false;
var actualHtml;
var actualTitle;
var actualError;
var expectedTitle = 'MyTitle';
var expectedHtml = '<span style="color:red">Test</span>';
// <snippet module="ui/web-view" title="WebView">
// ### Using WebView
// ``` JavaScript
webView.on(webViewModule.WebView.loadFinishedEvent, function (args: webViewModule.LoadEventData) {
// <hide>
if (webView.ios) {
actualHtml = webView.ios.stringByEvaluatingJavaScriptFromString("document.body.innerHTML").trim();
} else if (webView.android) {
actualTitle = webView.android.getTitle()
}
actualError = args.error;
testFinished = true;
// </hide>
var message;
if (!args.error) {
message = "WebView finished loading " + args.url;
}
else {
message = "Error loading " + args.url + ": " + args.error;
}
//console.log(message);
});
webView.src = '<!DOCTYPE html><html><head><title>MyTitle</title><meta charset="utf-8" /></head><body><span style="color:red">Test</span></body></html>';
TKUnit.wait(4);
helper.goBack();
if (testFinished) {
if (webView.ios) {
TKUnit.assert(actualHtml === expectedHtml, "HTML string not loaded properly. Actual: " + actualHtml);
} else if (webView.android) {
TKUnit.assert(actualTitle === expectedTitle, "HTML string not loaded properly. Actual: " + actualTitle);
}
TKUnit.assert(actualError === undefined, actualError);
}
else {
TKUnit.assert(false, "TIMEOUT");
}
}
export var testLoadInvalidUrl = function () {
var newPage: page.Page;
var webView = _createWebViewFunc();

View File

@ -7,6 +7,8 @@
<TabViewItem.view>
<StackLayout>
<WebView src="&lt;html&gt;&lt;body&gt;&lt;span style='color:red'&gt;Test&lt;/span&gt;&lt;/body&gt;&lt;/html&gt;" />
<!--<ToolBar>
<ToolBar.items>
<ToolBarItem>

View File

@ -1,11 +1,9 @@
import http = require("http");
import types = require("utils/types");
import utils = require("utils/utils");
// This is used for definition purposes only, it does not generate JavaScript for it.
import definition = require("image-source");
var RESOURCE_PREFIX = "res://";
export function fromResource(name: string): definition.ImageSource {
var image = new definition.ImageSource();
return image.loadFromResource(name) ? image : null;
@ -40,18 +38,12 @@ export function fromFileOrResource(path: string): definition.ImageSource {
throw new Error("Path \"" + "\" is not a valid file or resource.");
}
if (path.indexOf(RESOURCE_PREFIX) === 0) {
return fromResource(path.substr(RESOURCE_PREFIX.length));
if (path.indexOf(utils.RESOURCE_PREFIX) === 0) {
return fromResource(path.substr(utils.RESOURCE_PREFIX.length));
}
return fromFile(path);
}
export function isFileOrResourcePath(path: string): boolean {
if (!types.isString(path)) {
return false;
}
return path.indexOf("~/") === 0 || // relative to AppRoot
path.indexOf("/") === 0 || // absolute path
path.indexOf(RESOURCE_PREFIX) === 0; // resource
return utils.isFileOrResourcePath(path);
}

View File

@ -118,7 +118,7 @@ declare module "image-source" {
export function fromFileOrResource(path: string): ImageSource;
/**
* Returns true if the specified path points to a resource or local file.
* [Obsolete. Please use utils.isFileOrResourcePath instead!] Returns true if the specified path points to a resource or local file.
* @param path The path.
*/
export function isFileOrResourcePath(path: string): boolean

View File

@ -22,11 +22,31 @@ function onUrlPropertyChanged(data: dependencyObservable.PropertyChangeData) {
// register the setNativeValue callback
(<proxy.PropertyMetadata>urlProperty.metadata).onSetNativeValue = onUrlPropertyChanged;
var srcProperty = new dependencyObservable.Property(
"src",
"WebView",
new proxy.PropertyMetadata("")
);
function onSrcPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var webView = <WebView>data.object;
if (webView._suspendLoading) {
return;
}
webView._loadSrc(data.newValue);
}
// register the setNativeValue callback
(<proxy.PropertyMetadata>srcProperty.metadata).onSetNativeValue = onSrcPropertyChanged;
export class WebView extends view.View implements definition.WebView {
public static loadStartedEvent = "loadStarted";
public static loadFinishedEvent = "loadFinished";
public static urlProperty = urlProperty;
public static srcProperty = srcProperty;
public _suspendLoading: boolean;
@ -42,6 +62,14 @@ export class WebView extends view.View implements definition.WebView {
this._setValue(WebView.urlProperty, value);
}
get src(): string {
return this._getValue(WebView.srcProperty);
}
set src(value: string) {
this._setValue(WebView.srcProperty, value);
}
public _onLoadFinished(url: string, error?: string) {
this._suspendLoading = true;
@ -73,6 +101,10 @@ export class WebView extends view.View implements definition.WebView {
throw new Error("This member is abstract.");
}
public _loadSrc(src: string) {
throw new Error("This member is abstract.");
}
get canGoBack(): boolean {
throw new Error("This member is abstract.");
}

View File

@ -1,5 +1,7 @@
import common = require("ui/web-view/web-view-common");
import trace = require("trace");
import utils = require("utils/utils");
import fs = require("file-system");
declare var exports;
require("utils/module-merge").merge(common, exports);
@ -74,6 +76,31 @@ export class WebView extends common.WebView {
this._android.loadUrl(url);
}
public _loadSrc(src: string) {
trace.write("WebView._loadSrc(" + src + ")", trace.categories.Debug);
this._android.stopLoading();
this._android.loadUrl("about:blank");
if (utils.isFileOrResourcePath(src)) {
if (src.indexOf("~/") === 0) {
src = fs.path.join(fs.knownFolders.currentApp().path, src.replace("~/", ""));
}
var file = fs.File.fromPath(src);
if (file) {
file.readText().then((r) => {
this._android.loadData(r, "text/html", null);
});
}
} else if (src.indexOf("http://") === 0 || src.indexOf("https://") === 0) {
this._android.loadUrl(src);
} else {
this._android.loadData(src, "text/html", null);
}
}
get canGoBack(): boolean {
return this._android.canGoBack();
}

View File

@ -36,10 +36,15 @@ declare module "ui/web-view" {
ios: UIWebView;
/**
* Gets or sets the url displayed by this instance.
* [Obsolete. Please use src instead!] Gets or sets the url displayed by this instance.
*/
url: string;
/**
* Gets or sets the url, local file path or HTML string.
*/
src: string;
/**
* Gets a value indicating whether the WebView can navigate back.
*/

View File

@ -1,5 +1,7 @@
import common = require("ui/web-view/web-view-common");
import trace = require("trace");
import utils = require("utils/utils");
import fs = require("file-system");
declare var exports;
require("utils/module-merge").merge(common, exports);
@ -17,16 +19,16 @@ class UIWebViewDelegateImpl extends NSObject implements UIWebViewDelegate {
this._owner = owner;
return this;
}
public webViewShouldStartLoadWithRequestNavigationType(webView: UIWebView, request: NSURLRequest, navigationType: number) {
if (request.URL) {
trace.write("UIWebViewDelegateClass.webViewShouldStartLoadWithRequestNavigationType(" + request.URL.absoluteString + ", " + navigationType + ")", trace.categories.Debug);
this._owner._onLoadStarted(request.URL.absoluteString);
}
return true;
}
public webViewDidStartLoad(webView: UIWebView) {
trace.write("UIWebViewDelegateClass.webViewDidStartLoad(" + webView.request.URL + ")", trace.categories.Debug);
}
@ -81,6 +83,32 @@ export class WebView extends common.WebView {
this._ios.loadRequest(NSURLRequest.requestWithURL(NSURL.URLWithString(url)));
}
public _loadSrc(src: string) {
trace.write("WebView._loadSrc(" + src + ")", trace.categories.Debug);
if (this._ios.loading) {
this._ios.stopLoading();
}
if (utils.isFileOrResourcePath(src)) {
if (src.indexOf("~/") === 0) {
src = fs.path.join(fs.knownFolders.currentApp().path, src.replace("~/", ""));
}
var file = fs.File.fromPath(src);
if (file) {
file.readText().then((r) => {
this._ios.loadHTMLStringBaseURL(r, null);
});
}
} else if (src.indexOf("http://") === 0 || src.indexOf("https://") === 0) {
this._ios.loadRequest(NSURLRequest.requestWithURL(NSURL.URLWithString(src)));
} else {
this._ios.loadHTMLStringBaseURL(src, null);
}
}
get canGoBack(): boolean {
return this._ios.canGoBack;
}

View File

@ -1,5 +1,7 @@
import types = require("utils/types");
export var RESOURCE_PREFIX = "res://";
export function copyFrom(source: any, target: any) {
if (types.isDefined(source) && types.isDefined(target)) {
var i: number;
@ -50,4 +52,14 @@ export module layout {
export function getMeasureSpecSize(spec: number): number {
return (spec & ~MODE_MASK);
}
}
export function isFileOrResourcePath(path: string): boolean {
if (!types.isString(path)) {
return false;
}
return path.indexOf("~/") === 0 || // relative to AppRoot
path.indexOf("/") === 0 || // absolute path
path.indexOf(RESOURCE_PREFIX) === 0; // resource
}

8
utils/utils.d.ts vendored
View File

@ -2,6 +2,8 @@
import colorModule = require("color");
import view = require("ui/core/view");
export var RESOURCE_PREFIX: string;
/**
* Utility module related to layout.
*/
@ -132,4 +134,10 @@
* An utility function that invokes garbage collection on the JavaScript side.
*/
export function GC();
/**
* Returns true if the specified path points to a resource or local file.
* @param path The path.
*/
export function isFileOrResourcePath(path: string): boolean
}