Compare commits

...

63 Commits

Author SHA1 Message Date
Andrew Grieve
4d3c7b17d2 Add NOTICE file 2014-02-27 15:45:10 -05:00
Andrew Grieve
17ba417572 Merge branch 'master' into dev
Conflicts:
	RELEASENOTES.md
	plugin.xml
2014-02-27 12:01:26 -05:00
Andrew Grieve
77085aa547 CB-6114 Updated version and RELEASENOTES.md for release 0.3.2 2014-02-27 11:56:29 -05:00
Ian Clelland
26702cb072 Validate that callbackId is correctly formed 2014-02-19 00:26:19 -05:00
Bryan Higgins
39e64c988a CB-6035 - Move js-module so it is not loaded on unsupported platforms
BlackBerry 10 has a native implementation which does not require the plugin.
2014-02-13 15:00:18 -05:00
Steven Gill
cd31b3a64d CB-5980 Incremented plugin version on dev branch. 2014-02-10 15:23:01 -08:00
Steven Gill
4c07917c0a CB-5980 Updated version and RELEASENOTES.md for release 0.3.1 2014-02-10 15:23:01 -08:00
Sidney Bofah
24e6a1feeb Removed some iOS6 Deprecations 2014-02-10 15:37:23 -05:00
Steven Gill
b62b9edde3 CB-5980 Updated version and RELEASENOTES.md for release 0.3.1 2014-02-05 17:53:59 -08:00
Andrew Grieve
985d94ee00 Add missing import for previous commit 2014-01-19 21:56:59 -05:00
Ian Clelland
e807bc3dc0 CB-5756: Android: Use WebView.evaluateJavascript for script injection on Android 4.4+ 2014-01-19 21:22:02 -05:00
Joe Bowser
0ce0eed585 Didn't test on ICS or lower, getDrawable isn't supported until Jellybean 2014-01-16 13:55:53 -08:00
Joe Bowser
736c8ddec0 WTF? ubuntu got automerged twice 2014-01-16 11:34:47 -08:00
Maxim Ermilov
9206d82df4 add ubuntu platform 2014-01-16 11:33:45 -08:00
Joe Bowser
bc554fdf95 Adding CC-A-2.5 Notice for Assets, modifying plugins to use resources 2014-01-16 11:33:44 -08:00
Joe Bowser
43f8935541 Adding the buttons 2014-01-16 11:33:44 -08:00
Joe Bowser
2136cad49a Adding drawables to the inAppBrowser. This doesn't look quite right, but it's a HUGE improvement over the previous settings 2014-01-16 11:33:44 -08:00
Ian Clelland
9795b2e9dc CB-5756: Add missing import 2014-01-13 15:09:38 -05:00
Ian Clelland
255c5269c3 CB-5756: Android: Use WebView.evaluateJavascript for script injection on Android 4.4+ 2014-01-13 14:34:32 -05:00
Andrew Grieve
21fe13e809 Delete stale test/ directory 2014-01-08 21:11:43 -05:00
Andrew Grieve
3f9af4fd88 Remove _alive from InAppBrowser.js since it didn't catch the case where the browser is closed by the user. 2014-01-07 10:52:44 -05:00
Andrew Grieve
57d14da151 CB-5733 Fix IAB.close() not working if called before show() animation is done
Also attempts to fix some thread warnings by doing show/hide on
separate event loop cycles.
2014-01-07 10:52:38 -05:00
Andrew Grieve
21a1638ccf CB-5719 Incremented plugin version on dev branch. 2014-01-02 12:30:52 -05:00
Andrew Grieve
b0bdb1088b CB-5719 Updated version and RELEASENOTES.md for release 0.3.0 2014-01-02 12:24:02 -05:00
Andrew Grieve
6163f17aeb CB-5592 Add a comment explaining why we set MIME only for file: 2013-12-20 11:10:33 -05:00
gianluca
176890f305 CB-5592 Android - Add MIME type to Intent when opening file:/// URLs
To avoid the "No Activity found to handle Intent..." error.
2013-12-20 11:06:10 -05:00
Andrew Grieve
2bd006b71e CB-5658 Update license comment formatting of doc/index.md 2013-12-18 21:11:02 -05:00
Andrew Grieve
aac2db29b5 CB-5658 Add doc.index.md for InAppBrowser plugin 2013-12-18 15:31:18 -05:00
Andrew Grieve
97c6f2ba8a CB-5658 Delete stale snapshot of plugin docs 2013-12-17 20:49:39 -05:00
ivan baktsheev
f75b30857b CB-5594 Add disallowoverscroll option.
Similar to the main cordova webview
2013-12-13 09:25:46 -05:00
Andrew Grieve
25d152b578 CB-5595 Rename "toolbarbarpostion" -> "toolbarposition" 2013-12-13 09:17:49 -05:00
Peter Somogyvari
4aeaf81e1e CB-5595 Fixed the positioning and autoresizing for certain rotation scenarios.
The autoresizing masks are applied conditonally based on the
browserOptions.toolbarposition flag to ensure that the toolbar is in
its correct place. Also added a utility function to query the
necessary offset for the status bar: the function takes care of the iOS
version and orientation caused differences without hardcoding the value
as 20 pixels.
2013-12-13 09:17:11 -05:00
Peter Somogyvari
20611efe67 CB-5595 Add toolbarposition=top option.
The position of the toolbar is now configurable, it can be specified on
the caller's side. The possible values are top and bottom and the key
for the setting is toolbarposition. Also extended the logging of the web
view's load errors, it now logs the error code too, not just the
localized description of the error that occured. Added the
browserOptions to the init method's parameters in order to make it
conveniently accessible from the ViewController.
2013-12-13 09:16:04 -05:00
Dick van den Brink
e819041fd4 Apply CB-5193 to InAppBrowser
From pull request:
https://github.com/apache/cordova-plugin-inappbrowser/pull/11
2013-12-06 10:07:41 -05:00
Tomáš Fejfar
034b599315 CB-5593 iOS: Make InAppBrowser localizable
Wrapping all UI strings in NSLocalizedString macro
2013-12-06 09:42:22 -05:00
Fco. Javier Martín Carrasco
f448ce88ab CB-5591 Change window.escape to encodeURIComponent
escape is for JS, encodeURIComponent is for URLs. This is a URL.
2013-12-06 09:14:15 -05:00
Steven Gill
ea239151d2 [CB-5565] Incremented plugin version on dev branch. 2013-12-04 15:32:03 -08:00
Steven Gill
496ecc720f [CB-5565] Updated version and RELEASENOTES.md for release 0.2.5 2013-12-04 15:16:31 -08:00
Jesse MacFadyen
30525d545a Merge branch 'dev' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-inappbrowser into dev 2013-12-03 13:50:16 -08:00
Jesse MacFadyen
8a549547cb Merge branch 'dev' of https://github.com/Yangtb/cordova-plugin-inappbrowser into dev 2013-12-03 13:42:50 -08:00
Ian Clelland
65ee3d142f Remove merge conflict tag 2013-12-02 20:53:17 -05:00
Jesse MacFadyen
fadb170e50 Merge branch 'dev' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-inappbrowser into dev 2013-12-02 17:51:28 -08:00
Jesse MacFadyen
9768ec2ef0 CB-3420 WP feature hidden=yes implemented 2013-12-02 17:50:57 -08:00
Steven Gill
d2b644e5d5 Added ubuntu support 2013-12-02 16:28:32 -08:00
Archana Naik
e5101ba8e1 Added amazon-fireos platform.
Change to use amazon-fireos as the platform if user agent string contains 'cordova-amazon-fireos'
2013-10-30 13:36:04 -07:00
Steven Gill
d49d6ec62f CB-5188: 2013-10-28 12:27:15 -07:00
Steven Gill
a8060219d5 fixed merge conflict 2013-10-28 12:13:43 -07:00
Steven Gill
e5868f8ecb [CB-5188] Updated version and RELEASENOTES.md for release 0.2.4 2013-10-28 12:03:26 -07:00
hermwong
b3348cff6c CB-5128: added repo + issue tag to plugin.xml for inappbrowser plugin 2013-10-22 13:40:00 -07:00
Andrew Grieve
aa81c3267a CB-4995 Fix crash when WebView is quickly opened then closed.
Also fixes a leak where callback was never being cleared.
2013-10-21 13:19:13 -04:00
Maxim Ermilov
a8f79e1fd6 add ubuntu platform 2013-10-16 21:13:03 +04:00
Shazron Abdullah
c7972b6cff CB-4930 - iOS - InAppBrowser should take into account the status bar 2013-10-15 15:00:09 -07:00
Steven Gill
ce7a796cb0 [CB-5010] Incremented plugin version on dev branch. 2013-10-10 10:56:18 -07:00
Steven Gill
a76a0a3920 [CB-5010] Updated version and RELEASENOTES.md for release 0.2.3 2013-10-10 10:56:18 -07:00
Andrew Grieve
5ef5171003 CB-4858 - Run IAB methods on the UI thread. 2013-10-10 12:40:27 -04:00
Andrew Grieve
8a6bc01814 CB-4858 Convert relative URLs to absolute URLs in JS 2013-10-10 12:21:35 -04:00
Andrew Grieve
8df4b7d03b CB-3747 Fix back button having different dismiss logic from the close button.
Also made the IAB close when the owner page is navigated (implemented
onReset).
2013-10-10 11:51:58 -04:00
Andrew Grieve
8cd786b603 CB-5021 Expose closeDialog() as a public function and make it safe to call multiple times. 2013-10-10 08:07:46 -04:00
Andrew Grieve
ef5eddac9a CB-5021 Make it safe to call close() multiple times 2013-10-09 21:25:24 -04:00
Steven Gill
4d4d479b3c [CB-5010] Updated version and RELEASENOTES.md for release 0.2.3 2013-10-09 15:27:18 -07:00
Steven Gill
3d8b04f982 [CB-4915] Incremented plugin version on dev branch. 2013-09-26 15:26:55 -07:00
Carlos Santana
12bc5d7d8b [CB-4926] Fixes inappbrowser plugin loading for windows8 2013-09-26 13:53:33 -04:00
Yangtb
e5862bf820 [CB-4724] fixed UriFormatException
fixed UriFormatException & InvalidOperationException
2013-09-11 16:18:47 +08:00
43 changed files with 2144 additions and 1714 deletions

5
NOTICE Normal file
View File

@@ -0,0 +1,5 @@
Apache Cordova
Copyright 2012 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).

View File

@@ -1,5 +1,22 @@
cordova-plugin-inappbrowser
-----------------------------
To install this plugin, follow the [Command-line Interface Guide](http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface).
<!---
license: Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
If you are not using the Cordova Command-line Interface, follow [Using Plugman to Manage Plugins](http://cordova.apache.org/docs/en/edge/plugin_ref_plugman.md.html).
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# org.apache.cordova.inappbrowser
Plugin documentation: [doc/index.md](doc/index.md)

View File

@@ -32,3 +32,49 @@
* Rename CHANGELOG.md -> RELEASENOTES.md
* [CB-4792] Added keepCallback to the show function.
* [CB-4752] Incremented plugin version on dev branch.
### 0.2.3 (Oct 9, 2013)
* [CB-4915] Incremented plugin version on dev branch.
* [CB-4926] Fixes inappbrowser plugin loading for windows8
### 0.2.4 (Oct 28, 2013)
* CB-5128: added repo + issue tag to plugin.xml for inappbrowser plugin
* CB-4995 Fix crash when WebView is quickly opened then closed.
* CB-4930 - iOS - InAppBrowser should take into account the status bar
* [CB-5010] Incremented plugin version on dev branch.
* [CB-5010] Updated version and RELEASENOTES.md for release 0.2.3
* CB-4858 - Run IAB methods on the UI thread.
* CB-4858 Convert relative URLs to absolute URLs in JS
* CB-3747 Fix back button having different dismiss logic from the close button.
* CB-5021 Expose closeDialog() as a public function and make it safe to call multiple times.
* CB-5021 Make it safe to call close() multiple times
### 0.2.5 (Dec 4, 2013)
* Remove merge conflict tag
* [CB-4724] fixed UriFormatException
* add ubuntu platform
* CB-3420 WP feature hidden=yes implemented
* Added amazon-fireos platform. Change to use amazon-fireos as the platform if user agent string contains 'cordova-amazon-fireos'
### 0.3.0 (Jan 02, 2014)
* CB-5592 Android: Add MIME type to Intent when opening file:/// URLs
* CB-5594 iOS: Add disallowoverscroll option.
* CB-5658 Add doc/index.md for InAppBrowser plugin
* CB-5595 Add toolbarposition=top option.
* Apply CB-5193 to InAppBrowser (Fix DB quota exception)
* CB-5593 iOS: Make InAppBrowser localizable
* CB-5591 Change window.escape to encodeURIComponent
### 0.3.1 (Feb 05, 2014)
* CB-5756: Android: Use WebView.evaluateJavascript for script injection on Android 4.4+
* Didn't test on ICS or lower, getDrawable isn't supported until Jellybean
* add ubuntu platform
* Adding drawables to the inAppBrowser. This doesn't look quite right, but it's a HUGE improvement over the previous settings
* CB-5756: Android: Use WebView.evaluateJavascript for script injection on Android 4.4+
* Remove alive from InAppBrowser.js since it didn't catch the case where the browser is closed by the user.
* CB-5733 Fix IAB.close() not working if called before show() animation is done
### 0.3.2 (Feb 26, 2014)
* Validate that callbackId is correctly formed
* CB-6035 Move js-module so it is not loaded on unsupported platforms
* Removed some iOS6 Deprecations

280
doc/index.md Normal file
View File

@@ -0,0 +1,280 @@
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# org.apache.cordova.inappbrowser
This plugin provides a web browser view that displays when calling `window.open()`, or when opening a link formed as `<a target="_blank">`.
var ref = window.open('http://apache.org', '_blank', 'location=yes');
__NOTE__: The InAppBrowser window behaves like a standard web browser,
and can't access Cordova APIs.
## Installation
cordova plugin add org.apache.cordova.inappbrowser
## window.open
Opens a URL in a new `InAppBrowser` instance, the current browser
instance, or the system browser.
var ref = window.open(url, target, options);
- __ref__: Reference to the `InAppBrowser` window. _(InAppBrowser)_
- __url__: The URL to load _(String)_. Call `encodeURI()` on this if the URL contains Unicode characters.
- __target__: The target in which to load the URL, an optional parameter that defaults to `_self`. _(String)_
- `_self`: Opens in the Cordova WebView if the URL is in the white list, otherwise it opens in the `InAppBrowser`.
- `_blank`: Opens in the `InAppBrowser`.
- `_system`: Opens in the system's web browser.
- __options__: Options for the `InAppBrowser`. Optional, defaulting to: `location=yes`. _(String)_
The `options` string must not contain any blank space, and each feature's name/value pairs must be separated by a comma. Feature names are case insensitive. All platforms support the value below:
- __location__: Set to `yes` or `no` to turn the `InAppBrowser`'s location bar on or off.
Android only:
- __closebuttoncaption__: set to a string to use as the __Done__ button's caption.
- __hidden__: set to `yes` to create the browser and load the page, but not show it. The load event fires when loading is complete. Omit or set to `no` (default) to have the browser open and load normally.
- __clearcache__: set to `yes` to have the browser's cookie cache cleared before the new window is opened
- __clearsessioncache__: set to `yes` to have the session cookie cache cleared before the new window is opened
iOS only:
- __closebuttoncaption__: set to a string to use as the __Done__ button's caption. Note that you need to localize this value yourself.
- __disallowoverscroll__: Set to `yes` or `no` (default is `no`). Turns on/off the UIWebViewBounce property.
- __hidden__: set to `yes` to create the browser and load the page, but not show it. The load event fires when loading is complete. Omit or set to `no` (default) to have the browser open and load normally.
- __toolbar__: set to `yes` or `no` to turn the toolbar on or off for the InAppBrowser (defaults to `yes`)
- __enableViewportScale__: Set to `yes` or `no` to prevent viewport scaling through a meta tag (defaults to `no`).
- __mediaPlaybackRequiresUserAction__: Set to `yes` or `no` to prevent HTML5 audio or video from autoplaying (defaults to `no`).
- __allowInlineMediaPlayback__: Set to `yes` or `no` to allow in-line HTML5 media playback, displaying within the browser window rather than a device-specific playback interface. The HTML's `video` element must also include the `webkit-playsinline` attribute (defaults to `no`)
- __keyboardDisplayRequiresUserAction__: Set to `yes` or `no` to open the keyboard when form elements receive focus via JavaScript's `focus()` call (defaults to `yes`).
- __suppressesIncrementalRendering__: Set to `yes` or `no` to wait until all new view content is received before being rendered (defaults to `no`).
- __presentationstyle__: Set to `pagesheet`, `formsheet` or `fullscreen` to set the [presentation style](http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalPresentationStyle) (defaults to `fullscreen`).
- __transitionstyle__: Set to `fliphorizontal`, `crossdissolve` or `coververtical` to set the [transition style](http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle) (defaults to `coververtical`).
- __toolbarposition__: Set to `top` or `bottom` (default is `bottom`). Causes the toolbar to be at the top or bottom of the window.
### Supported Platforms
- Amazon Fire OS
- Android
- BlackBerry 10
- iOS
- Windows Phone 7 and 8
### Example
var ref = window.open('http://apache.org', '_blank', 'location=yes');
var ref2 = window.open(encodeURI('http://ja.m.wikipedia.org/wiki/ハングル'), '_blank', 'location=yes');
## InAppBrowser
The object returned from a call to `window.open`.
### Methods
- addEventListener
- removeEventListener
- close
- show
- executeScript
- insertCSS
## addEventListener
> Adds a listener for an event from the `InAppBrowser`.
ref.addEventListener(eventname, callback);
- __ref__: reference to the `InAppBrowser` window _(InAppBrowser)_
- __eventname__: the event to listen for _(String)_
- __loadstart__: event fires when the `InAppBrowser` starts to load a URL.
- __loadstop__: event fires when the `InAppBrowser` finishes loading a URL.
- __loaderror__: event fires when the `InAppBrowser` encounters an error when loading a URL.
- __exit__: event fires when the `InAppBrowser` window is closed.
- __callback__: the function that executes when the event fires. The function is passed an `InAppBrowserEvent` object as a parameter.
### InAppBrowserEvent Properties
- __type__: the eventname, either `loadstart`, `loadstop`, `loaderror`, or `exit`. _(String)_
- __url__: the URL that was loaded. _(String)_
- __code__: the error code, only in the case of `loaderror`. _(Number)_
- __message__: the error message, only in the case of `loaderror`. _(String)_
### Supported Platforms
- Amazon Fire OS
- Android
- BlackBerry 10
- iOS
- Windows Phone 7 and 8
### Quick Example
var ref = window.open('http://apache.org', '_blank', 'location=yes');
ref.addEventListener('loadstart', function() { alert(event.url); });
## removeEventListener
> Removes a listener for an event from the `InAppBrowser`.
ref.removeEventListener(eventname, callback);
- __ref__: reference to the `InAppBrowser` window. _(InAppBrowser)_
- __eventname__: the event to stop listening for. _(String)_
- __loadstart__: event fires when the `InAppBrowser` starts to load a URL.
- __loadstop__: event fires when the `InAppBrowser` finishes loading a URL.
- __loaderror__: event fires when the `InAppBrowser` encounters an error loading a URL.
- __exit__: event fires when the `InAppBrowser` window is closed.
- __callback__: the function to execute when the event fires.
The function is passed an `InAppBrowserEvent` object.
### Supported Platforms
- Amazon Fire OS
- Android
- BlackBerry 10
- iOS
- Windows Phone 7 and 8
### Quick Example
var ref = window.open('http://apache.org', '_blank', 'location=yes');
var myCallback = function() { alert(event.url); }
ref.addEventListener('loadstart', myCallback);
ref.removeEventListener('loadstart', myCallback);
## close
> Closes the `InAppBrowser` window.
ref.close();
- __ref__: reference to the `InAppBrowser` window _(InAppBrowser)_
### Supported Platforms
- Amazon Fire OS
- Android
- BlackBerry 10
- iOS
- Windows Phone 7 and 8
### Quick Example
var ref = window.open('http://apache.org', '_blank', 'location=yes');
ref.close();
## show
> Displays an InAppBrowser window that was opened hidden. Calling this has no effect if the InAppBrowser was already visible.
ref.show();
- __ref__: reference to the InAppBrowser window (`InAppBrowser`)
### Supported Platforms
- Amazon Fire OS
- Android
- BlackBerry 10
- iOS
### Quick Example
var ref = window.open('http://apache.org', '_blank', 'hidden=yes');
// some time later...
ref.show();
## executeScript
> Injects JavaScript code into the `InAppBrowser` window
ref.executeScript(details, callback);
- __ref__: reference to the `InAppBrowser` window. _(InAppBrowser)_
- __injectDetails__: details of the script to run, specifying either a `file` or `code` key. _(Object)_
- __file__: URL of the script to inject.
- __code__: Text of the script to inject.
- __callback__: the function that executes after the JavaScript code is injected.
- If the injected script is of type `code`, the callback executes
with a single parameter, which is the return value of the
script, wrapped in an `Array`. For multi-line scripts, this is
the return value of the last statement, or the last expression
evaluated.
### Supported Platforms
- Amazon Fire OS
- Android
- BlackBerry 10
- iOS
### Quick Example
var ref = window.open('http://apache.org', '_blank', 'location=yes');
ref.addEventListener('loadstop', function() {
ref.executeScript({file: "myscript.js"});
});
## insertCSS
> Injects CSS into the `InAppBrowser` window.
ref.insertCSS(details, callback);
- __ref__: reference to the `InAppBrowser` window _(InAppBrowser)_
- __injectDetails__: details of the script to run, specifying either a `file` or `code` key. _(Object)_
- __file__: URL of the stylesheet to inject.
- __code__: Text of the stylesheet to inject.
- __callback__: the function that executes after the CSS is injected.
### Supported Platforms
- Amazon Fire OS
- Android
- BlackBerry 10
- iOS
### Quick Example
var ref = window.open('http://apache.org', '_blank', 'location=yes');
ref.addEventListener('loadstop', function() {
ref.insertCSS({file: "mystyles.css"});
});

View File

@@ -1,427 +0,0 @@
---
license: Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
---
InAppBrowser
============
> The `InAppBrowser` is a web browser that displays in the app when calling `window.open`.
var ref = window.open('http://apache.org', '_blank', 'location=yes');
Description
-----------
The object returned from a call to `window.open`.
Methods
----------
- addEventListener
- removeEventListener
- close
Permissions
-----------
### Android
#### app/res/xml/config.xml
<plugin name="InAppBrowser" value="org.apache.cordova.InAppBrowser" />
### iOS
#### config.xml
<plugin name="InAppBrowser" value="CDVInAppBrowser" />
### Windows Phone 7 + 8
#### config.xml
<plugin name="InAppBrowser" />
addEventListener
================
> Adds a listener for an event from the `InAppBrowser`.
ref.addEventListener(eventname, callback);
- __ref__: reference to the `InAppBrowser` window _(InAppBrowser)_
- __eventname__: the event to listen for _(String)_
- __loadstart__: event fires when the `InAppBrowser` starts to load a URL.
- __loadstop__: event fires when the `InAppBrowser` finishes loading a URL.
- __loaderror__: event fires when the `InAppBrowser` encounters an error when loading a URL.
- __exit__: event fires when the `InAppBrowser` window is closed.
- __callback__: the function that executes when the event fires. The function is passed an `InAppBrowserEvent` object as a parameter.
Supported Platforms
-------------------
- Android
- iOS
- Windows Phone 7 + 8
Quick Example
-------------
var ref = window.open('http://apache.org', '_blank', 'location=yes');
ref.addEventListener('loadstart', function() { alert(event.url); });
Full Example
------------
<!DOCTYPE html>
<html>
<head>
<title>InAppBrowser.addEventListener Example</title>
<script type="text/javascript" charset="utf-8" src="cordova-x.x.x.js"></script>
<script type="text/javascript" charset="utf-8">
// Wait for device API libraries to load
//
document.addEventListener("deviceready", onDeviceReady, false);
// device APIs are available
//
function onDeviceReady() {
var ref = window.open('http://apache.org', '_blank', 'location=yes');
ref.addEventListener('loadstart', function(event) { alert('start: ' + event.url); });
ref.addEventListener('loadstop', function(event) { alert('stop: ' + event.url); });
ref.addEventListener('loaderror', function(event) { alert('error: ' + event.message); });
ref.addEventListener('exit', function(event) { alert(event.type); });
}
</script>
</head>
<body>
</body>
</html>
removeEventListener
===================
> Removes a listener for an event from the `InAppBrowser`.
ref.removeEventListener(eventname, callback);
- __ref__: reference to the `InAppBrowser` window. _(InAppBrowser)_
- __eventname__: the event to stop listening for. _(String)_
- __loadstart__: event fires when the `InAppBrowser` starts to load a URL.
- __loadstop__: event fires when the `InAppBrowser` finishes loading a URL.
- __loaderror__: event fires when the `InAppBrowser` encounters an error loading a URL.
- __exit__: event fires when the `InAppBrowser` window is closed.
- __callback__: the function to execute when the event fires.
The function is passed an `InAppBrowserEvent` object.
Supported Platforms
-------------------
- Android
- iOS
- Windows Phone 7 + 8
Quick Example
-------------
var ref = window.open('http://apache.org', '_blank', 'location=yes');
var myCallback = function() { alert(event.url); }
ref.addEventListener('loadstart', myCallback);
ref.removeEventListener('loadstart', myCallback);
Full Example
------------
<!DOCTYPE html>
<html>
<head>
<title>InAppBrowser.removeEventListener Example</title>
<script type="text/javascript" charset="utf-8" src="cordova-x.x.x.js"></script>
<script type="text/javascript" charset="utf-8">
// Wait for device API libraries to load
//
document.addEventListener("deviceready", onDeviceReady, false);
// Global InAppBrowser reference
var iabRef = null;
function iabLoadStart(event) {
alert(event.type + ' - ' + event.url);
}
function iabLoadStop(event) {
alert(event.type + ' - ' + event.url);
}
function iabLoadError(event) {
alert(event.type + ' - ' + event.message);
}
function iabClose(event) {
alert(event.type);
iabRef.removeEventListener('loadstart', iabLoadStart);
iabRef.removeEventListener('loadstop', iabLoadStop);
iabRef.removeEventListener('loaderror', iabLoadError);
iabRef.removeEventListener('exit', iabClose);
}
// device APIs are available
//
function onDeviceReady() {
iabRef = window.open('http://apache.org', '_blank', 'location=yes');
iabRef.addEventListener('loadstart', iabLoadStart);
iabRef.addEventListener('loadstop', iabLoadStop);
iabRef.removeEventListener('loaderror', iabLoadError);
iabRef.addEventListener('exit', iabClose);
}
</script>
</head>
<body>
</body>
</html>
close
=====
> Closes the `InAppBrowser` window.
ref.close();
- __ref__: reference to the `InAppBrowser` window _(InAppBrowser)_
Supported Platforms
-------------------
- Android
- iOS
- Windows Phone 7 + 8
- BlackBerry 10
Quick Example
-------------
var ref = window.open('http://apache.org', '_blank', 'location=yes');
ref.close();
Full Example
------------
<!DOCTYPE html>
<html>
<head>
<title>InAppBrowser.close Example</title>
<script type="text/javascript" charset="utf-8" src="cordova-x.x.x.js"></script>
<script type="text/javascript" charset="utf-8">
// Wait for device API libraries to load
//
document.addEventListener("deviceready", onDeviceReady, false);
// device APIs are available
//
function onDeviceReady() {
var ref = window.open('http://apache.org', '_blank', 'location=yes');
// close InAppBrowser after 5 seconds
setTimeout(function() {
ref.close();
}, 5000);
}
</script>
</head>
<body>
</body>
</html>
executeScript
=============
> Injects JavaScript code into the `InAppBrowser` window
ref.executeScript(details, callback);
- __ref__: reference to the `InAppBrowser` window. _(InAppBrowser)_
- __injectDetails__: details of the script to run, specifying either a `file` or `code` key. _(Object)_
- __file__: URL of the script to inject.
- __code__: Text of the script to inject.
- __callback__: the function that executes after the JavaScript code is injected.
- If the injected script is of type `code`, the callback executes
with a single parameter, which is the return value of the
script, wrapped in an `Array`. For multi-line scripts, this is
the return value of the last statement, or the last expression
evaluated.
Supported Platforms
-------------------
- Android
- iOS
Quick Example
-------------
var ref = window.open('http://apache.org', '_blank', 'location=yes');
ref.addEventListener('loadstop', function() {
ref.executeSript({file: "myscript.js"});
});
Full Example
------------
<!DOCTYPE html>
<html>
<head>
<title>InAppBrowser.executeScript Example</title>
<script type="text/javascript" charset="utf-8" src="cordova-x.x.x.js"></script>
<script type="text/javascript" charset="utf-8">
// Wait for device API libraries to load
//
document.addEventListener("deviceready", onDeviceReady, false);
// Global InAppBrowser reference
var iabRef = null;
// Inject our custom JavaScript into the InAppBrowser window
//
function replaceHeaderImage() {
iabRef.executeScript({
code: "var img=document.querySelector('#header img'); img.src='http://cordova.apache.org/images/cordova_bot.png';"
}, function() {
alert("Image Element Successfully Hijacked");
}
}
function iabClose(event) {
iabRef.removeEventListener('loadstop', replaceHeaderImage);
iabRef.removeEventListener('exit', iabClose);
}
// device APIs are available
//
function onDeviceReady() {
iabRef = window.open('http://apache.org', '_blank', 'location=yes');
iabRef.addEventListener('loadstop', replaceHeaderImage);
iabRef.addEventListener('exit', iabClose);
}
</script>
</head>
<body>
</body>
</html>
insertCSS
=========
> Injects CSS into the `InAppBrowser` window.
ref.insertCSS(details, callback);
- __ref__: reference to the `InAppBrowser` window _(InAppBrowser)_
- __injectDetails__: details of the script to run, specifying either a `file` or `code` key. _(Object)_
- __file__: URL of the stylesheet to inject.
- __code__: Text of the stylesheet to inject.
- __callback__: the function that executes after the CSS is injected.
Supported Platforms
-------------------
- Android
- iOS
Quick Example
-------------
var ref = window.open('http://apache.org', '_blank', 'location=yes');
ref.addEventListener('loadstop', function() {
ref.insertCSS({file: "mystyles.css"});
});
Full Example
------------
<!DOCTYPE html>
<html>
<head>
<title>InAppBrowser.executeScript Example</title>
<script type="text/javascript" charset="utf-8" src="cordova-x.x.x.js"></script>
<script type="text/javascript" charset="utf-8">
// Wait for device API libraries to load
//
document.addEventListener("deviceready", onDeviceReady, false);
// Global InAppBrowser reference
var iabRef = null;
// Inject our custom CSS into the InAppBrowser window
//
function changeBackgroundColor() {
iabRef.executeScript({
code: "body { background: #ffff00"
}, function() {
alert("Styles Altered");
}
}
function iabClose(event) {
iabRef.removeEventListener('loadstop', changeBackgroundColor);
iabRef.removeEventListener('exit', iabClose);
}
// device APIs are available
//
function onDeviceReady() {
iabRef = window.open('http://apache.org', '_blank', 'location=yes');
iabRef.addEventListener('loadstop', changeBackgroundColor);
iabRef.addEventListener('exit', iabClose);
}
</script>
</head>
<body>
</body>
</html>
InAppBrowserEvent
=================
The object that is passed to the callback function from an
`addEventListener` call on an `InAppBrowser` object.
Properties
----------
- __type__: the eventname, either `loadstart`, `loadstop`, `loaderror`, or `exit`. _(String)_
- __url__: the URL that was loaded. _(String)_
- __code__: the error code, only in the case of `loaderror`. _(Number)_
- __message__: the error message, only in the case of `loaderror`. _(String)_

View File

@@ -1,100 +0,0 @@
---
license: Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
---
window.open
===========
Opens a URL in a new `InAppBrowser` instance, the current browser
instance, or the system browser.
var ref = window.open(url, target, options);
- __ref__: Reference to the `InAppBrowser` window. _(InAppBrowser)_
- __url__: The URL to load _(String)_. Call `encodeURI()` on this if the URL contains Unicode characters.
- __target__: The target in which to load the URL, an optional parameter that defaults to `_self`. _(String)_
- `_self`: Opens in the Cordova WebView if the URL is in the white list, otherwise it opens in the `InAppBrowser`.
- `_blank`: Opens in the `InAppBrowser`.
- `_system`: Opens in the system's web browser.
- __options__: Options for the `InAppBrowser`. Optional, defaulting to: `location=yes`. _(String)_
The `options` string must not contain any blank space, and each feature's name/value pairs must be separated by a comma. Feature names are case insensitive. All platforms support the value below:
- __location__: Set to `yes` or `no` to turn the `InAppBrowser`'s location bar on or off.
Android only
------------
- __closebuttoncaption__ - set to a string that will be the caption for the "Done" button.
iOS only
--------
- __closebuttoncaption__ - set to a string that will be the caption for the "Done" button. Note that you will have to localize this value yourself.
- __toolbar__ - set to 'yes' or 'no' to turn the toolbar on or off for the InAppBrowser (defaults to 'yes')
- __enableViewportScale__: Set to `yes` or `no` to prevent viewport scaling through a meta tag (defaults to `no`).
- __mediaPlaybackRequiresUserAction__: Set to `yes` or `no` to prevent HTML5 audio or video from autoplaying (defaults to `no`).
- __allowInlineMediaPlayback__: Set to `yes` or `no` to allow inline HTML5 media playback, displaying within the browser window rather than a device-specific playback interface. The HTML's `video` element must also include the `webkit-playsinline` attribute (defaults to `no`)
- __keyboardDisplayRequiresUserAction__: Set to `yes` or `no` to open the keyboard when form elements receive focus via JavaScript's `focus()` call (defaults to `yes`).
- __suppressesIncrementalRendering__: Set to `yes` or `no` to wait until all new view content is received before being rendered (defaults to `no`).
- __presentationstyle__: Set to `pagesheet`, `formsheet` or `fullscreen` to set the [presentation style](http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalPresentationStyle) (defaults to `fullscreen`).
- __transitionstyle__: Set to `fliphorizontal`, `crossdissolve` or `coververtical` to set the [transition style](http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle) (defaults to `coververtical`).
Supported Platforms
-------------------
- Android
- iOS
- BlackBerry 10
- Windows Phone 7 + 8
Quick Example
-------------
var ref = window.open('http://apache.org', '_blank', 'location=yes');
var ref2 = window.open(encodeURI('http://ja.m.wikipedia.org/wiki/ハングル'), '_blank', 'location=yes');
Full Example
------------
<!DOCTYPE html>
<html>
<head>
<title>window.open Example</title>
<script type="text/javascript" charset="utf-8" src="cordova-x.x.x.js"></script>
<script type="text/javascript" charset="utf-8">
// Wait for device API libraries to load
//
document.addEventListener("deviceready", onDeviceReady, false);
// device APIs are available
//
function onDeviceReady() {
// external url
var ref = window.open(encodeURI('http://apache.org'), '_blank', 'location=yes');
// relative document
ref = window.open('next.html', '_self');
}
</script>
</head>
<body>
</body>
</html>

View File

@@ -2,19 +2,24 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="org.apache.cordova.inappbrowser"
version="0.2.2">
version="0.3.2">
<name>InAppBrowser</name>
<description>Cordova InAppBrowser Plugin</description>
<license>Apache 2.0</license>
<keywords>cordova,in,app,browser,inappbrowser</keywords>
<repo>https://git-wip-us.apache.org/repos/asf/cordova-plugin-inappbrowser.git</repo>
<issue>https://issues.apache.org/jira/browse/CB/component/12320641</issue>
<js-module src="www/InAppBrowser.js" name="InAppBrowser">
<clobbers target="window.open" />
</js-module>
<engines>
<engine name="cordova" version=">=3.1.0" /><!-- Needs cordova/urlutil -->
</engines>
<!-- android -->
<platform name="android">
<js-module src="www/inappbrowser.js" name="inappbrowser">
<clobbers target="window.open" />
</js-module>
<config-file target="res/xml/config.xml" parent="/*">
<feature name="InAppBrowser">
<param name="android-package" value="org.apache.cordova.inappbrowser.InAppBrowser"/>
@@ -23,10 +28,56 @@
<source-file src="src/android/InAppBrowser.java" target-dir="src/org/apache/cordova/inappbrowser" />
<source-file src="src/android/InAppChromeClient.java" target-dir="src/org/apache/cordova/inappbrowser" />
<!-- drawable src/android/resources -->
<resource-file src="src/android/res/drawable-hdpi/ic_action_next_item.png" target="res/drawable-hdpi/ic_action_next_item.png" />
<resource-file src="src/android/res/drawable-mdpi/ic_action_next_item.png" target="res/drawable-mdpi/ic_action_next_item.png" />
<resource-file src="src/android/res/drawable-xhdpi/ic_action_next_item.png" target="res/drawable-xhdpi/ic_action_next_item.png" />
<resource-file src="src/android/res/drawable-xxhdpi/ic_action_next_item.png" target="res/drawable-xxhdpi/ic_action_next_item.png" />
<resource-file src="src/android/res/drawable-hdpi/ic_action_previous_item.png" target="res/drawable-hdpi/ic_action_previous_item.png" />
<resource-file src="src/android/res/drawable-mdpi/ic_action_previous_item.png" target="res/drawable-mdpi/ic_action_previous_item.png" />
<resource-file src="src/android/res/drawable-xhdpi/ic_action_previous_item.png" target="res/drawable-xhdpi/ic_action_previous_item.png" />
<resource-file src="src/android/res/drawable-xxhdpi/ic_action_previous_item.png" target="res/drawable-xxhdpi/ic_action_previous_item.png" />
<resource-file src="src/android/res/drawable-hdpi/ic_action_remove.png" target="res/drawable-hdpi/ic_action_remove.png" />
<resource-file src="src/android/res/drawable-mdpi/ic_action_remove.png" target="res/drawable-mdpi/ic_action_remove.png" />
<resource-file src="src/android/res/drawable-xhdpi/ic_action_remove.png" target="res/drawable-xhdpi/ic_action_remove.png" />
<resource-file src="src/android/res/drawable-xxhdpi/ic_action_remove.png" target="res/drawable-xxhdpi/ic_action_remove.png" />
</platform>
<!-- amazon-fireos -->
<platform name="amazon-fireos">
<js-module src="www/inappbrowser.js" name="inappbrowser">
<clobbers target="window.open" />
</js-module>
<config-file target="res/xml/config.xml" parent="/*">
<feature name="InAppBrowser">
<param name="android-package" value="org.apache.cordova.inappbrowser.InAppBrowser"/>
</feature>
</config-file>
<source-file src="src/amazon/InAppBrowser.java" target-dir="src/org/apache/cordova/inappbrowser" />
<source-file src="src/amazon/InAppChromeClient.java" target-dir="src/org/apache/cordova/inappbrowser" />
</platform>
<!-- ubuntu -->
<platform name="ubuntu">
<js-module src="www/inappbrowser.js" name="inappbrowser">
<clobbers target="window.open" />
</js-module>
<header-file src="src/ubuntu/inappbrowser.h" />
<source-file src="src/ubuntu/inappbrowser.cpp" />
<resource-file src="src/ubuntu/InAppBrowser.qml" />
<resource-file src="src/ubuntu/close.png" />
</platform>
<!-- ios -->
<platform name="ios">
<platform name="ios">
<js-module src="www/inappbrowser.js" name="inappbrowser">
<clobbers target="window.open" />
</js-module>
<config-file target="config.xml" parent="/*">
<feature name="InAppBrowser">
<param name="ios-package" value="CDVInAppBrowser" />
@@ -39,15 +90,11 @@
<framework src="CoreGraphics.framework" />
</platform>
<!-- blackberry10 -->
<!-- <platform name="blackberry10">
<config-file target="www/config.xml" parent="/widget">
<feature name="InAppBrowser" value="InAppBrowser"/>
</config-file>
</platform>
-->
<!-- wp7 -->
<platform name="wp7">
<js-module src="www/inappbrowser.js" name="inappbrowser">
<clobbers target="window.open" />
</js-module>
<config-file target="config.xml" parent="/*">
<feature name="InAppBrowser">
<param name="wp-package" value="InAppBrowser"/>
@@ -59,6 +106,9 @@
<!-- wp8 -->
<platform name="wp8">
<js-module src="www/inappbrowser.js" name="inappbrowser">
<clobbers target="window.open" />
</js-module>
<config-file target="config.xml" parent="/*">
<feature name="InAppBrowser">
<param name="wp-package" value="InAppBrowser"/>
@@ -70,6 +120,9 @@
<!-- windows8 -->
<platform name="windows8">
<js-module src="www/inappbrowser.js" name="inappbrowser">
<clobbers target="window.open" />
</js-module>
<js-module src="www/windows8/InAppBrowserProxy.js" name="InAppBrowserProxy">
<merges target="" />
</js-module>

View File

@@ -0,0 +1,769 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova.inappbrowser;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import com.amazon.android.webkit.AmazonWebChromeClient;
import com.amazon.android.webkit.AmazonGeolocationPermissions.Callback;
import com.amazon.android.webkit.AmazonJsPromptResult;
import com.amazon.android.webkit.AmazonWebSettings;
import com.amazon.android.webkit.AmazonWebStorage;
import com.amazon.android.webkit.AmazonWebView;
import com.amazon.android.webkit.AmazonWebViewClient;
import com.amazon.android.webkit.AmazonCookieManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.Config;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.apache.cordova.CordovaActivity;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.StringTokenizer;
@SuppressLint("SetJavaScriptEnabled")
public class InAppBrowser extends CordovaPlugin {
private static final String NULL = "null";
protected static final String LOG_TAG = "InAppBrowser";
private static final String SELF = "_self";
private static final String SYSTEM = "_system";
// private static final String BLANK = "_blank";
private static final String EXIT_EVENT = "exit";
private static final String LOCATION = "location";
private static final String HIDDEN = "hidden";
private static final String LOAD_START_EVENT = "loadstart";
private static final String LOAD_STOP_EVENT = "loadstop";
private static final String LOAD_ERROR_EVENT = "loaderror";
private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption";
private static final String CLEAR_ALL_CACHE = "clearcache";
private static final String CLEAR_SESSION_CACHE = "clearsessioncache";
private Dialog dialog;
private AmazonWebView inAppWebView;
private EditText edittext;
private CallbackContext callbackContext;
private boolean showLocationBar = true;
private boolean openWindowHidden = false;
private String buttonLabel = "Done";
private boolean clearAllCache= false;
private boolean clearSessionCache=false;
/**
* Executes the request and returns PluginResult.
*
* @param action The action to execute.
* @param args JSONArry of arguments for the plugin.
* @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message.
*/
public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
if (action.equals("open")) {
this.callbackContext = callbackContext;
final String url = args.getString(0);
String t = args.optString(1);
if (t == null || t.equals("") || t.equals(NULL)) {
t = SELF;
}
final String target = t;
final HashMap<String, Boolean> features = parseFeature(args.optString(2));
Log.d(LOG_TAG, "target = " + target);
this.cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
String result = "";
// SELF
if (SELF.equals(target)) {
Log.d(LOG_TAG, "in self");
// load in webview
if (url.startsWith("file://") || url.startsWith("javascript:")
|| Config.isUrlWhiteListed(url)) {
webView.loadUrl(url);
}
//Load the dialer
else if (url.startsWith(AmazonWebView.SCHEME_TEL))
{
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
cordova.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
}
// load in InAppBrowser
else {
result = showWebPage(url, features);
}
}
// SYSTEM
else if (SYSTEM.equals(target)) {
Log.d(LOG_TAG, "in system");
result = openExternal(url);
}
// BLANK - or anything else
else {
Log.d(LOG_TAG, "in blank");
result = showWebPage(url, features);
}
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);
}
});
}
else if (action.equals("close")) {
closeDialog();
}
else if (action.equals("injectScriptCode")) {
String jsWrapper = null;
if (args.getBoolean(1)) {
jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectScriptFile")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectStyleCode")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectStyleFile")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("show")) {
this.cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.show();
}
});
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
pluginResult.setKeepCallback(true);
this.callbackContext.sendPluginResult(pluginResult);
}
else {
return false;
}
return true;
}
/**
* Called when the view navigates.
*/
@Override
public void onReset() {
closeDialog();
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
closeDialog();
}
/**
* Inject an object (script or style) into the InAppBrowser AmazonWebView.
*
* This is a helper method for the inject{Script|Style}{Code|File} API calls, which
* provides a consistent method for injecting JavaScript code into the document.
*
* If a wrapper string is supplied, then the source string will be JSON-encoded (adding
* quotes) and wrapped using string formatting. (The wrapper string should have a single
* '%s' marker)
*
* @param source The source object (filename or script/style text) to inject into
* the document.
* @param jsWrapper A JavaScript string to wrap the source string in, so that the object
* is properly injected, or null if the source string is JavaScript text
* which should be executed directly.
*/
private void injectDeferredObject(String source, String jsWrapper) {
final String scriptToInject;
if (jsWrapper != null) {
org.json.JSONArray jsonEsc = new org.json.JSONArray();
jsonEsc.put(source);
String jsonRepr = jsonEsc.toString();
String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
scriptToInject = String.format(jsWrapper, jsonSourceString);
} else {
scriptToInject = source;
}
final String finalScriptToInject = scriptToInject;
// This action will have the side-effect of blurring the currently focused element
this.cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
inAppWebView.loadUrl("javascript:" + finalScriptToInject);
}
});
}
/**
* Put the list of features into a hash map
*
* @param optString
* @return
*/
private HashMap<String, Boolean> parseFeature(String optString) {
if (optString.equals(NULL)) {
return null;
} else {
HashMap<String, Boolean> map = new HashMap<String, Boolean>();
StringTokenizer features = new StringTokenizer(optString, ",");
StringTokenizer option;
while(features.hasMoreElements()) {
option = new StringTokenizer(features.nextToken(), "=");
if (option.hasMoreElements()) {
String key = option.nextToken();
if (key.equalsIgnoreCase(CLOSE_BUTTON_CAPTION)) {
this.buttonLabel = option.nextToken();
} else {
Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE;
map.put(key, value);
}
}
}
return map;
}
}
/**
* Display a new browser with the specified URL.
*
* @param url The url to load.
* @param usePhoneGap Load url in PhoneGap webview
* @return "" if ok, or error message.
*/
public String openExternal(String url) {
try {
Intent intent = null;
intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
this.cordova.getActivity().startActivity(intent);
return "";
} catch (android.content.ActivityNotFoundException e) {
Log.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString());
return e.toString();
}
}
/**
* Closes the dialog
*/
public void closeDialog() {
this.cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
if (dialog != null) {
dialog.dismiss();
}
}
});
}
/**
* Checks to see if it is possible to go back one page in history, then does so.
*/
private void goBack() {
this.cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
if (InAppBrowser.this.inAppWebView.canGoBack()) {
InAppBrowser.this.inAppWebView.goBack();
}
}
});
}
/**
* Checks to see if it is possible to go forward one page in history, then does so.
*/
private void goForward() {
this.cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
if (InAppBrowser.this.inAppWebView.canGoForward()) {
InAppBrowser.this.inAppWebView.goForward();
}
}
});
}
/**
* Navigate to the new page
*
* @param url to load
*/
private void navigate(final String url) {
InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
this.cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
if (!url.startsWith("http") && !url.startsWith("file:")) {
InAppBrowser.this.inAppWebView.loadUrl("http://" + url);
} else {
InAppBrowser.this.inAppWebView.loadUrl(url);
}
InAppBrowser.this.inAppWebView.requestFocus();
}
});
}
/**
* Should we show the location bar?
*
* @return boolean
*/
private boolean getShowLocationBar() {
return this.showLocationBar;
}
/**
* Display a new browser with the specified URL.
*
* @param url The url to load.
* @param jsonObject
*/
public String showWebPage(final String url, HashMap<String, Boolean> features) {
// Determine if we should hide the location bar.
showLocationBar = true;
openWindowHidden = false;
if (features != null) {
Boolean show = features.get(LOCATION);
if (show != null) {
showLocationBar = show.booleanValue();
}
Boolean hidden = features.get(HIDDEN);
if (hidden != null) {
openWindowHidden = hidden.booleanValue();
}
Boolean cache = features.get(CLEAR_ALL_CACHE);
if (cache != null) {
clearAllCache = cache.booleanValue();
} else {
cache = features.get(CLEAR_SESSION_CACHE);
if (cache != null) {
clearSessionCache = cache.booleanValue();
}
}
}
final CordovaWebView thatWebView = this.webView;
// Create dialog in new thread
Runnable runnable = new Runnable() {
/**
* Convert our DIP units to Pixels
*
* @return int
*/
private int dpToPixels(int dipValue) {
int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP,
(float) dipValue,
cordova.getActivity().getResources().getDisplayMetrics()
);
return value;
}
public void run() {
// Let's create the main dialog
dialog = new Dialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar);
dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog;
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(true);
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
closeDialog();
}
});
// Main container layout
LinearLayout main = new LinearLayout(cordova.getActivity());
main.setOrientation(LinearLayout.VERTICAL);
// Toolbar layout
RelativeLayout toolbar = new RelativeLayout(cordova.getActivity());
//Please, no more black!
toolbar.setBackgroundColor(android.graphics.Color.LTGRAY);
toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44)));
toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2));
toolbar.setHorizontalGravity(Gravity.LEFT);
toolbar.setVerticalGravity(Gravity.TOP);
// Action Button Container layout
RelativeLayout actionButtonContainer = new RelativeLayout(cordova.getActivity());
actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
actionButtonContainer.setHorizontalGravity(Gravity.LEFT);
actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);
actionButtonContainer.setId(1);
// Back button
Button back = new Button(cordova.getActivity());
RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT);
back.setLayoutParams(backLayoutParams);
back.setContentDescription("Back Button");
back.setId(2);
back.setText("<");
back.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
goBack();
}
});
// Forward button
Button forward = new Button(cordova.getActivity());
RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2);
forward.setLayoutParams(forwardLayoutParams);
forward.setContentDescription("Forward Button");
forward.setId(3);
forward.setText(">");
forward.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
goForward();
}
});
// Edit Text Box
edittext = new EditText(cordova.getActivity());
RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1);
textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5);
edittext.setLayoutParams(textLayoutParams);
edittext.setId(4);
edittext.setSingleLine(true);
edittext.setText(url);
edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
edittext.setImeOptions(EditorInfo.IME_ACTION_GO);
edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE
edittext.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
// If the event is a key-down event on the "enter" button
if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
navigate(edittext.getText().toString());
return true;
}
return false;
}
});
// Close button
Button close = new Button(cordova.getActivity());
RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
close.setLayoutParams(closeLayoutParams);
forward.setContentDescription("Close Button");
close.setId(5);
close.setText(buttonLabel);
close.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
closeDialog();
}
});
// WebView
inAppWebView = new AmazonWebView(cordova.getActivity());
CordovaActivity app = (CordovaActivity) cordova.getActivity();
cordova.getFactory().initializeWebView(inAppWebView, 0x00FF00, false, null);
inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView));
AmazonWebViewClient client = new InAppBrowserClient(thatWebView, edittext);
inAppWebView.setWebViewClient(client);
AmazonWebSettings settings = inAppWebView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
settings.setBuiltInZoomControls(true);
settings.setPluginState(com.amazon.android.webkit.AmazonWebSettings.PluginState.ON);
//Toggle whether this is enabled or not!
Bundle appSettings = cordova.getActivity().getIntent().getExtras();
boolean enableDatabase = appSettings == null ? true : appSettings.getBoolean("InAppBrowserStorageEnabled", true);
if (enableDatabase) {
String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
settings.setDatabasePath(databasePath);
settings.setDatabaseEnabled(true);
}
settings.setDomStorageEnabled(true);
if (clearAllCache) {
AmazonCookieManager.getInstance().removeAllCookie();
} else if (clearSessionCache) {
AmazonCookieManager.getInstance().removeSessionCookie();
}
inAppWebView.loadUrl(url);
inAppWebView.setId(6);
inAppWebView.getSettings().setLoadWithOverviewMode(true);
inAppWebView.getSettings().setUseWideViewPort(true);
inAppWebView.requestFocus();
inAppWebView.requestFocusFromTouch();
// Add the back and forward buttons to our action button container layout
actionButtonContainer.addView(back);
actionButtonContainer.addView(forward);
// Add the views to our toolbar
toolbar.addView(actionButtonContainer);
toolbar.addView(edittext);
toolbar.addView(close);
// Don't add the toolbar if its been disabled
if (getShowLocationBar()) {
// Add our toolbar to our main view/layout
main.addView(toolbar);
}
// Add our webview to our main view/layout
main.addView(inAppWebView);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(dialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.MATCH_PARENT;
dialog.setContentView(main);
dialog.show();
dialog.getWindow().setAttributes(lp);
// the goal of openhidden is to load the url and not display it
// Show() needs to be called to cause the URL to be loaded
if(openWindowHidden) {
dialog.hide();
}
}
};
this.cordova.getActivity().runOnUiThread(runnable);
return "";
}
/**
* Create a new plugin success result and send it back to JavaScript
*
* @param obj a JSONObject contain event payload information
*/
private void sendUpdate(JSONObject obj, boolean keepCallback) {
sendUpdate(obj, keepCallback, PluginResult.Status.OK);
}
/**
* Create a new plugin result and send it back to JavaScript
*
* @param obj a JSONObject contain event payload information
* @param status the status code to return to the JavaScript environment
*/
private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
if (callbackContext != null) {
PluginResult result = new PluginResult(status, obj);
result.setKeepCallback(keepCallback);
callbackContext.sendPluginResult(result);
if (!keepCallback) {
callbackContext = null;
}
}
}
/**
* The webview client receives notifications about appView
*/
public class InAppBrowserClient extends AmazonWebViewClient {
EditText edittext;
CordovaWebView webView;
/**
* Constructor.
*
* @param mContext
* @param edittext
*/
public InAppBrowserClient(CordovaWebView webView, EditText mEditText) {
this.webView = webView;
this.edittext = mEditText;
}
/**
* Notify the host application that a page has started loading.
*
* @param view The webview initiating the callback.
* @param url The url of the page.
*/
@Override
public void onPageStarted(AmazonWebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
String newloc = "";
if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
newloc = url;
}
// If dialing phone (tel:5551212)
else if (url.startsWith(AmazonWebView.SCHEME_TEL)) {
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
cordova.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
}
else if (url.startsWith("geo:") || url.startsWith(AmazonWebView.SCHEME_MAILTO) || url.startsWith("market:")) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
cordova.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString());
}
}
// If sms:5551212?body=This is the message
else if (url.startsWith("sms:")) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
// Get address
String address = null;
int parmIndex = url.indexOf('?');
if (parmIndex == -1) {
address = url.substring(4);
}
else {
address = url.substring(4, parmIndex);
// If body, then set sms body
Uri uri = Uri.parse(url);
String query = uri.getQuery();
if (query != null) {
if (query.startsWith("body=")) {
intent.putExtra("sms_body", query.substring(5));
}
}
}
intent.setData(Uri.parse("sms:" + address));
intent.putExtra("address", address);
intent.setType("vnd.android-dir/mms-sms");
cordova.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
}
}
else {
newloc = "http://" + url;
}
if (!newloc.equals(edittext.getText().toString())) {
edittext.setText(newloc);
}
try {
JSONObject obj = new JSONObject();
obj.put("type", LOAD_START_EVENT);
obj.put("url", newloc);
sendUpdate(obj, true);
} catch (JSONException ex) {
Log.d(LOG_TAG, "Should never happen");
}
}
public void onPageFinished(AmazonWebView view, String url) {
super.onPageFinished(view, url);
try {
JSONObject obj = new JSONObject();
obj.put("type", LOAD_STOP_EVENT);
obj.put("url", url);
sendUpdate(obj, true);
} catch (JSONException ex) {
Log.d(LOG_TAG, "Should never happen");
}
}
public void onReceivedError(AmazonWebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
try {
JSONObject obj = new JSONObject();
obj.put("type", LOAD_ERROR_EVENT);
obj.put("url", failingUrl);
obj.put("code", errorCode);
obj.put("message", description);
sendUpdate(obj, true, PluginResult.Status.ERROR);
} catch (JSONException ex) {
Log.d(LOG_TAG, "Should never happen");
}
}
}
}

View File

@@ -0,0 +1,128 @@
package org.apache.cordova.inappbrowser;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import com.amazon.android.webkit.AmazonWebChromeClient;
import com.amazon.android.webkit.AmazonGeolocationPermissions.Callback;
import com.amazon.android.webkit.AmazonJsPromptResult;
import com.amazon.android.webkit.AmazonWebStorage;
import com.amazon.android.webkit.AmazonWebView;
import com.amazon.android.webkit.AmazonWebViewClient;
public class InAppChromeClient extends AmazonWebChromeClient {
private CordovaWebView webView;
private String LOG_TAG = "InAppChromeClient";
private long MAX_QUOTA = 100 * 1024 * 1024;
public InAppChromeClient(CordovaWebView webView) {
super();
this.webView = webView;
}
/**
* Handle database quota exceeded notification.
*
* @param url
* @param databaseIdentifier
* @param currentQuota
* @param estimatedSize
* @param totalUsedQuota
* @param quotaUpdater
*/
@Override
public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
long totalUsedQuota, AmazonWebStorage.QuotaUpdater quotaUpdater)
{
LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
if (estimatedSize < MAX_QUOTA)
{
//increase for 1Mb
long newQuota = estimatedSize;
LOG.d(LOG_TAG, "calling quotaUpdater.updateQuota newQuota: %d", newQuota);
quotaUpdater.updateQuota(newQuota);
}
else
{
// Set the quota to whatever it is and force an error
// TODO: get docs on how to handle this properly
quotaUpdater.updateQuota(currentQuota);
}
}
/**
* Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
*
* @param origin
* @param callback
*/
@Override
public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
super.onGeolocationPermissionsShowPrompt(origin, callback);
callback.invoke(origin, true, false);
}
/**
* Tell the client to display a prompt dialog to the user.
* If the client returns true, WebView will assume that the client will
* handle the prompt dialog and call the appropriate JsPromptResult method.
*
* The prompt bridge provided for the InAppBrowser is capable of executing any
* oustanding callback belonging to the InAppBrowser plugin. Care has been
* taken that other callbacks cannot be triggered, and that no other code
* execution is possible.
*
* To trigger the bridge, the prompt default value should be of the form:
*
* gap-iab://<callbackId>
*
* where <callbackId> is the string id of the callback to trigger (something
* like "InAppBrowser0123456789")
*
* If present, the prompt message is expected to be a JSON-encoded value to
* pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid.
*
* @param view
* @param url
* @param message
* @param defaultValue
* @param result
*/
@Override
public boolean onJsPrompt(AmazonWebView view, String url, String message, String defaultValue, AmazonJsPromptResult result) {
// See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute.
if (defaultValue != null && defaultValue.startsWith("gap")) {
if(defaultValue.startsWith("gap-iab://")) {
PluginResult scriptResult;
String scriptCallbackId = defaultValue.substring(10);
if (scriptCallbackId.startsWith("InAppBrowser")) {
if(message == null || message.length() == 0) {
scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray());
} else {
try {
scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message));
} catch(JSONException e) {
scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
}
}
this.webView.sendPluginResult(scriptResult, scriptCallbackId);
result.confirm("");
return true;
}
}
else
{
// Anything else with a gap: prefix should get this message
LOG.w(LOG_TAG, "InAppBrowser does not support Cordova API calls: " + url + " " + defaultValue);
result.cancel();
return true;
}
}
return false;
}
}

View File

@@ -18,27 +18,16 @@
*/
package org.apache.cordova.inappbrowser;
import java.util.HashMap;
import java.util.StringTokenizer;
import org.apache.cordova.Config;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
@@ -52,11 +41,7 @@ import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.webkit.CookieManager;
import android.webkit.WebChromeClient;
import android.webkit.GeolocationPermissions.Callback;
import android.webkit.JsPromptResult;
import android.webkit.WebSettings;
import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
@@ -64,6 +49,19 @@ import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.Config;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.StringTokenizer;
@SuppressLint("SetJavaScriptEnabled")
public class InAppBrowser extends CordovaPlugin {
@@ -100,120 +98,134 @@ public class InAppBrowser extends CordovaPlugin {
* @param callbackId The callback id used when calling back into JavaScript.
* @return A PluginResult object with a status and message.
*/
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
try {
if (action.equals("open")) {
this.callbackContext = callbackContext;
String url = args.getString(0);
String target = args.optString(1);
if (target == null || target.equals("") || target.equals(NULL)) {
target = SELF;
}
HashMap<String, Boolean> features = parseFeature(args.optString(2));
Log.d(LOG_TAG, "target = " + target);
url = updateUrl(url);
String result = "";
// SELF
if (SELF.equals(target)) {
Log.d(LOG_TAG, "in self");
// load in webview
if (url.startsWith("file://") || url.startsWith("javascript:")
|| Config.isUrlWhiteListed(url)) {
this.webView.loadUrl(url);
}
//Load the dialer
else if (url.startsWith(WebView.SCHEME_TEL))
{
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
this.cordova.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
if (action.equals("open")) {
this.callbackContext = callbackContext;
final String url = args.getString(0);
String t = args.optString(1);
if (t == null || t.equals("") || t.equals(NULL)) {
t = SELF;
}
final String target = t;
final HashMap<String, Boolean> features = parseFeature(args.optString(2));
Log.d(LOG_TAG, "target = " + target);
this.cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
String result = "";
// SELF
if (SELF.equals(target)) {
Log.d(LOG_TAG, "in self");
// load in webview
if (url.startsWith("file://") || url.startsWith("javascript:")
|| Config.isUrlWhiteListed(url)) {
webView.loadUrl(url);
}
//Load the dialer
else if (url.startsWith(WebView.SCHEME_TEL))
{
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
cordova.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
}
// load in InAppBrowser
else {
result = showWebPage(url, features);
}
}
// load in InAppBrowser
// SYSTEM
else if (SYSTEM.equals(target)) {
Log.d(LOG_TAG, "in system");
result = openExternal(url);
}
// BLANK - or anything else
else {
result = this.showWebPage(url, features);
Log.d(LOG_TAG, "in blank");
result = showWebPage(url, features);
}
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);
}
// SYSTEM
else if (SYSTEM.equals(target)) {
Log.d(LOG_TAG, "in system");
result = this.openExternal(url);
});
}
else if (action.equals("close")) {
closeDialog();
}
else if (action.equals("injectScriptCode")) {
String jsWrapper = null;
if (args.getBoolean(1)) {
jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectScriptFile")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectStyleCode")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectStyleFile")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("show")) {
this.cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.show();
}
// BLANK - or anything else
else {
Log.d(LOG_TAG, "in blank");
result = this.showWebPage(url, features);
}
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
pluginResult.setKeepCallback(true);
this.callbackContext.sendPluginResult(pluginResult);
}
else if (action.equals("close")) {
closeDialog();
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
}
else if (action.equals("injectScriptCode")) {
String jsWrapper = null;
if (args.getBoolean(1)) {
jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectScriptFile")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectStyleCode")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("injectStyleFile")) {
String jsWrapper;
if (args.getBoolean(1)) {
jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
} else {
jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
}
injectDeferredObject(args.getString(0), jsWrapper);
}
else if (action.equals("show")) {
Runnable runnable = new Runnable() {
@Override
public void run() {
dialog.show();
}
};
this.cordova.getActivity().runOnUiThread(runnable);
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
pluginResult.setKeepCallback(true);
this.callbackContext.sendPluginResult(pluginResult);
}
else {
return false;
}
} catch (JSONException e) {
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
});
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
pluginResult.setKeepCallback(true);
this.callbackContext.sendPluginResult(pluginResult);
}
else {
return false;
}
return true;
}
/**
* Called when the view navigates.
*/
@Override
public void onReset() {
closeDialog();
}
/**
* Called by AccelBroker when listener is to be shut down.
* Stop listener.
*/
public void onDestroy() {
closeDialog();
}
/**
* Inject an object (script or style) into the InAppBrowser WebView.
*
@@ -241,8 +253,19 @@ public class InAppBrowser extends CordovaPlugin {
} else {
scriptToInject = source;
}
// This action will have the side-effect of blurring the currently focused element
this.inAppWebView.loadUrl("javascript:" + scriptToInject);
final String finalScriptToInject = scriptToInject;
this.cordova.getActivity().runOnUiThread(new Runnable() {
@SuppressLint("NewApi")
@Override
public void run() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
// This action will have the side-effect of blurring the currently focused element
inAppWebView.loadUrl("javascript:" + finalScriptToInject);
} else {
inAppWebView.evaluateJavascript(finalScriptToInject, null);
}
}
});
}
/**
@@ -274,20 +297,6 @@ public class InAppBrowser extends CordovaPlugin {
}
}
/**
* Convert relative URL to full path
*
* @param url
* @return
*/
private String updateUrl(String url) {
Uri newUrl = Uri.parse(url);
if (newUrl.isRelative()) {
url = this.webView.getUrl().substring(0, this.webView.getUrl().lastIndexOf("/")+1) + url;
}
return url;
}
/**
* Display a new browser with the specified URL.
*
@@ -299,7 +308,14 @@ public class InAppBrowser extends CordovaPlugin {
try {
Intent intent = null;
intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
// Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
// Adding the MIME type to http: URLs causes them to not be handled by the downloader.
Uri uri = Uri.parse(url);
if ("file".equals(uri.getScheme())) {
intent.setDataAndType(uri, webView.getResourceApi().getMimeType(uri));
} else {
intent.setData(uri);
}
this.cordova.getActivity().startActivity(intent);
return "";
} catch (android.content.ActivityNotFoundException e) {
@@ -311,30 +327,30 @@ public class InAppBrowser extends CordovaPlugin {
/**
* Closes the dialog
*/
private void closeDialog() {
try {
final WebView childView = this.inAppWebView;
Runnable runnable = new Runnable() {
@Override
public void run() {
childView.loadUrl("about:blank");
public void closeDialog() {
final WebView childView = this.inAppWebView;
// The JS protects against multiple calls, so this should happen only when
// closeDialog() is called by other native code.
if (childView == null) {
return;
}
this.cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
childView.loadUrl("about:blank");
if (dialog != null) {
dialog.dismiss();
}
};
this.cordova.getActivity().runOnUiThread(runnable);
}
});
try {
JSONObject obj = new JSONObject();
obj.put("type", EXIT_EVENT);
sendUpdate(obj, false);
} catch (JSONException ex) {
Log.d(LOG_TAG, "Should never happen");
}
if (dialog != null) {
dialog.dismiss();
}
}
/**
@@ -438,14 +454,7 @@ public class InAppBrowser extends CordovaPlugin {
dialog.setCancelable(true);
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
try {
JSONObject obj = new JSONObject();
obj.put("type", EXIT_EVENT);
sendUpdate(obj, false);
} catch (JSONException e) {
Log.d(LOG_TAG, "Should never happen");
}
closeDialog();
}
});
@@ -476,7 +485,20 @@ public class InAppBrowser extends CordovaPlugin {
back.setLayoutParams(backLayoutParams);
back.setContentDescription("Back Button");
back.setId(2);
/*
back.setText("<");
*/
Resources activityRes = cordova.getActivity().getResources();
int backResId = activityRes.getIdentifier("ic_action_previous_item", "drawable", cordova.getActivity().getPackageName());
Drawable backIcon = activityRes.getDrawable(backResId);
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
{
back.setBackgroundDrawable(backIcon);
}
else
{
back.setBackground(backIcon);
}
back.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
goBack();
@@ -490,7 +512,17 @@ public class InAppBrowser extends CordovaPlugin {
forward.setLayoutParams(forwardLayoutParams);
forward.setContentDescription("Forward Button");
forward.setId(3);
forward.setText(">");
//forward.setText(">");
int fwdResId = activityRes.getIdentifier("ic_action_next_item", "drawable", cordova.getActivity().getPackageName());
Drawable fwdIcon = activityRes.getDrawable(fwdResId);
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
{
forward.setBackgroundDrawable(fwdIcon);
}
else
{
forward.setBackground(fwdIcon);
}
forward.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
goForward();
@@ -527,7 +559,17 @@ public class InAppBrowser extends CordovaPlugin {
close.setLayoutParams(closeLayoutParams);
forward.setContentDescription("Close Button");
close.setId(5);
close.setText(buttonLabel);
//close.setText(buttonLabel);
int closeResId = activityRes.getIdentifier("ic_action_remove", "drawable", cordova.getActivity().getPackageName());
Drawable closeIcon = activityRes.getDrawable(closeResId);
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
{
close.setBackgroundDrawable(closeIcon);
}
else
{
close.setBackground(closeIcon);
}
close.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
closeDialog();
@@ -620,10 +662,16 @@ public class InAppBrowser extends CordovaPlugin {
*
* @param obj a JSONObject contain event payload information
* @param status the status code to return to the JavaScript environment
*/ private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
PluginResult result = new PluginResult(status, obj);
result.setKeepCallback(keepCallback);
this.callbackContext.sendPluginResult(result);
*/
private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
if (callbackContext != null) {
PluginResult result = new PluginResult(status, obj);
result.setKeepCallback(keepCallback);
callbackContext.sendPluginResult(result);
if (!keepCallback) {
callbackContext = null;
}
}
}

View File

@@ -38,20 +38,7 @@ public class InAppChromeClient extends WebChromeClient {
long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
{
LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
if (estimatedSize < MAX_QUOTA)
{
//increase for 1Mb
long newQuota = estimatedSize;
LOG.d(LOG_TAG, "calling quotaUpdater.updateQuota newQuota: %d", newQuota);
quotaUpdater.updateQuota(newQuota);
}
else
{
// Set the quota to whatever it is and force an error
// TODO: get docs on how to handle this properly
quotaUpdater.updateQuota(currentQuota);
}
quotaUpdater.updateQuota(MAX_QUOTA);
}
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1021 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 B

View File

@@ -30,6 +30,7 @@
@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController;
@property (nonatomic, copy) NSString* callbackId;
@property (nonatomic, copy) NSRegularExpression *callbackIdPattern;
- (void)open:(CDVInvokedUrlCommand*)command;
- (void)close:(CDVInvokedUrlCommand*)command;
@@ -38,11 +39,34 @@
@end
@interface CDVInAppBrowserOptions : NSObject {}
@property (nonatomic, assign) BOOL location;
@property (nonatomic, assign) BOOL toolbar;
@property (nonatomic, copy) NSString* closebuttoncaption;
@property (nonatomic, copy) NSString* toolbarposition;
@property (nonatomic, copy) NSString* presentationstyle;
@property (nonatomic, copy) NSString* transitionstyle;
@property (nonatomic, assign) BOOL enableviewportscale;
@property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction;
@property (nonatomic, assign) BOOL allowinlinemediaplayback;
@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction;
@property (nonatomic, assign) BOOL suppressesincrementalrendering;
@property (nonatomic, assign) BOOL hidden;
@property (nonatomic, assign) BOOL disallowoverscroll;
+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options;
@end
@interface CDVInAppBrowserViewController : UIViewController <UIWebViewDelegate>{
@private
NSString* _userAgent;
NSString* _prevUserAgent;
NSInteger _userAgentLockToken;
CDVInAppBrowserOptions *_browserOptions;
CDVWebViewDelegate* _webViewDelegate;
}
@@ -61,29 +85,9 @@
- (void)close;
- (void)navigateTo:(NSURL*)url;
- (void)showLocationBar:(BOOL)show;
- (void)showToolBar:(BOOL)show;
- (void)showToolBar:(BOOL)show : (NSString *) toolbarPosition;
- (void)setCloseButtonTitle:(NSString*)title;
- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent;
- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent browserOptions: (CDVInAppBrowserOptions*) browserOptions;
@end
@interface CDVInAppBrowserOptions : NSObject {}
@property (nonatomic, assign) BOOL location;
@property (nonatomic, assign) BOOL toolbar;
@property (nonatomic, copy) NSString* closebuttoncaption;
@property (nonatomic, copy) NSString* presentationstyle;
@property (nonatomic, copy) NSString* transitionstyle;
@property (nonatomic, assign) BOOL enableviewportscale;
@property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction;
@property (nonatomic, assign) BOOL allowinlinemediaplayback;
@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction;
@property (nonatomic, assign) BOOL suppressesincrementalrendering;
@property (nonatomic, assign) BOOL hidden;
+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options;
@end
@end

View File

@@ -26,19 +26,28 @@
#define kInAppBrowserTargetSystem @"_system"
#define kInAppBrowserTargetBlank @"_blank"
#define kInAppBrowserToolbarBarPositionBottom @"bottom"
#define kInAppBrowserToolbarBarPositionTop @"top"
#define TOOLBAR_HEIGHT 44.0
#define LOCATIONBAR_HEIGHT 21.0
#define FOOTER_HEIGHT ((TOOLBAR_HEIGHT) + (LOCATIONBAR_HEIGHT))
#pragma mark CDVInAppBrowser
@interface CDVInAppBrowser () {
NSInteger _previousStatusBarStyle;
}
@end
@implementation CDVInAppBrowser
- (CDVInAppBrowser*)initWithWebView:(UIWebView*)theWebView
{
self = [super initWithWebView:theWebView];
if (self != nil) {
// your initialization here
_previousStatusBarStyle = -1;
_callbackIdPattern = nil;
}
return self;
@@ -51,12 +60,12 @@
- (void)close:(CDVInvokedUrlCommand*)command
{
if (self.inAppBrowserViewController != nil) {
[self.inAppBrowserViewController close];
self.inAppBrowserViewController = nil;
if (self.inAppBrowserViewController == nil) {
NSLog(@"IAB.close() called but it was already closed.");
return;
}
self.callbackId = nil;
// Things are cleaned up in browserExit.
[self.inAppBrowserViewController close];
}
- (BOOL) isSystemUrl:(NSURL*)url
@@ -105,9 +114,10 @@
- (void)openInInAppBrowser:(NSURL*)url withOptions:(NSString*)options
{
CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options];
if (self.inAppBrowserViewController == nil) {
NSString* originalUA = [CDVUserAgentUtil originalUserAgent];
self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA prevUserAgent:[self.commandDelegate userAgent]];
self.inAppBrowserViewController = [[CDVInAppBrowserViewController alloc] initWithUserAgent:originalUA prevUserAgent:[self.commandDelegate userAgent] browserOptions: browserOptions];
self.inAppBrowserViewController.navigationDelegate = self;
if ([self.viewController conformsToProtocol:@protocol(CDVScreenOrientationDelegate)]) {
@@ -115,10 +125,8 @@
}
}
CDVInAppBrowserOptions* browserOptions = [CDVInAppBrowserOptions parseOptions:options];
[self.inAppBrowserViewController showLocationBar:browserOptions.location];
[self.inAppBrowserViewController showToolBar:browserOptions.toolbar];
[self.inAppBrowserViewController showToolBar:browserOptions.toolbar :browserOptions.toolbarposition];
if (browserOptions.closebuttoncaption != nil) {
[self.inAppBrowserViewController setCloseButtonTitle:browserOptions.closebuttoncaption];
}
@@ -144,6 +152,18 @@
}
self.inAppBrowserViewController.modalTransitionStyle = transitionStyle;
// prevent webView from bouncing
if (browserOptions.disallowoverscroll) {
if ([self.inAppBrowserViewController.webView respondsToSelector:@selector(scrollView)]) {
((UIScrollView*)[self.inAppBrowserViewController.webView scrollView]).bounces = NO;
} else {
for (id subview in self.inAppBrowserViewController.webView.subviews) {
if ([[subview class] isSubclassOfClass:[UIScrollView class]]) {
((UIScrollView*)subview).bounces = NO;
}
}
}
}
// UIWebView options
self.inAppBrowserViewController.webView.scalesPageToFit = browserOptions.enableviewportscale;
@@ -154,19 +174,34 @@
self.inAppBrowserViewController.webView.suppressesIncrementalRendering = browserOptions.suppressesincrementalrendering;
}
if (! browserOptions.hidden) {
if (self.viewController.modalViewController != self.inAppBrowserViewController) {
[self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES];
}
}
[self.inAppBrowserViewController navigateTo:url];
if (!browserOptions.hidden) {
[self show:nil];
}
}
- (void)show:(CDVInvokedUrlCommand*)command
{
if ([self.inAppBrowserViewController isViewLoaded] && self.inAppBrowserViewController.view.window)
if (self.inAppBrowserViewController == nil) {
NSLog(@"Tried to show IAB after it was closed.");
return;
[self.viewController presentModalViewController:self.inAppBrowserViewController animated:YES];
}
if (_previousStatusBarStyle != -1) {
NSLog(@"Tried to show IAB while already shown");
return;
}
_previousStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;
UINavigationController* nav = [[UINavigationController alloc]
initWithRootViewController:self.inAppBrowserViewController];
nav.navigationBarHidden = YES;
// Run later to avoid the "took a long time" log message.
dispatch_async(dispatch_get_main_queue(), ^{
if (self.inAppBrowserViewController != nil) {
[self.viewController presentModalViewController:nav animated:YES];
}
});
}
- (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options
@@ -222,7 +257,7 @@
NSString* jsWrapper = nil;
if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) {
jsWrapper = [NSString stringWithFormat:@"_cdvIframeBridge.src='gap-iab://%@/'+window.escape(JSON.stringify([eval(%%@)]));", command.callbackId];
jsWrapper = [NSString stringWithFormat:@"_cdvIframeBridge.src='gap-iab://%@/'+encodeURIComponent(JSON.stringify([eval(%%@)]));", command.callbackId];
}
[self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
}
@@ -263,6 +298,23 @@
[self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
}
- (BOOL)isValidCallbackId:(NSString *)callbackId
{
NSError *err = nil;
// Initialize on first use
if (self.callbackIdPattern == nil) {
self.callbackIdPattern = [NSRegularExpression regularExpressionWithPattern:@"^InAppBrowser[0-9]{1,10}$" options:0 error:&err];
if (err != nil) {
// Couldn't initialize Regex; No is safer than Yes.
return NO;
}
}
if ([self.callbackIdPattern firstMatchInString:callbackId options:0 range:NSMakeRange(0, [callbackId length])]) {
return YES;
}
return NO;
}
/**
* The iframe bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging
* to the InAppBrowser plugin. Care has been taken that other callbacks cannot be triggered, and that no
@@ -289,7 +341,7 @@
NSString* scriptCallbackId = [url host];
CDVPluginResult* pluginResult = nil;
if ([scriptCallbackId hasPrefix:@"InAppBrowser"]) {
if ([self isValidCallbackId:scriptCallbackId]) {
NSString* scriptResult = [url path];
NSError* __autoreleasing error = nil;
@@ -355,13 +407,20 @@
if (self.callbackId != nil) {
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsDictionary:@{@"type":@"exit"}];
[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
self.callbackId = nil;
}
// Set navigationDelegate to nil to ensure no callbacks are received from it.
self.inAppBrowserViewController.navigationDelegate = nil;
// Don't recycle the ViewController since it may be consuming a lot of memory.
// Also - this is required for the PDF/User-Agent bug work-around.
self.inAppBrowserViewController = nil;
_previousStatusBarStyle = -1;
if (IsAtLeastiOSVersion(@"7.0")) {
[[UIApplication sharedApplication] setStatusBarStyle:_previousStatusBarStyle];
}
}
@end
@@ -372,12 +431,13 @@
@synthesize currentURL;
- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent
- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent browserOptions: (CDVInAppBrowserOptions*) browserOptions
{
self = [super init];
if (self != nil) {
_userAgent = userAgent;
_prevUserAgent = prevUserAgent;
_browserOptions = browserOptions;
_webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self];
[self createViews];
}
@@ -390,10 +450,10 @@
// We create the views in code for primarily for ease of upgrades and not requiring an external .xib to be included
CGRect webViewBounds = self.view.bounds;
webViewBounds.size.height -= FOOTER_HEIGHT;
BOOL toolbarIsAtBottom = ![_browserOptions.toolbarposition isEqualToString:kInAppBrowserToolbarBarPositionTop];
webViewBounds.size.height -= _browserOptions.location ? FOOTER_HEIGHT : TOOLBAR_HEIGHT;
self.webView = [[UIWebView alloc] initWithFrame:webViewBounds];
self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
[self.view addSubview:self.webView];
@@ -435,10 +495,13 @@
UIBarButtonItem* fixedSpaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
fixedSpaceButton.width = 20;
self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, (self.view.bounds.size.height - TOOLBAR_HEIGHT), self.view.bounds.size.width, TOOLBAR_HEIGHT)];
float toolbarY = toolbarIsAtBottom ? self.view.bounds.size.height - TOOLBAR_HEIGHT : 0.0;
CGRect toolbarFrame = CGRectMake(0.0, toolbarY, self.view.bounds.size.width, TOOLBAR_HEIGHT);
self.toolbar = [[UIToolbar alloc] initWithFrame:toolbarFrame];
self.toolbar.alpha = 1.000;
self.toolbar.autoresizesSubviews = YES;
self.toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
self.toolbar.autoresizingMask = toolbarIsAtBottom ? (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin) : UIViewAutoresizingFlexibleWidth;
self.toolbar.barStyle = UIBarStyleBlackOpaque;
self.toolbar.clearsContextBeforeDrawing = NO;
self.toolbar.clipsToBounds = NO;
@@ -450,7 +513,9 @@
self.toolbar.userInteractionEnabled = YES;
CGFloat labelInset = 5.0;
self.addressLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelInset, (self.view.bounds.size.height - FOOTER_HEIGHT), self.view.bounds.size.width - labelInset, LOCATIONBAR_HEIGHT)];
float locationBarY = toolbarIsAtBottom ? self.view.bounds.size.height - FOOTER_HEIGHT : self.view.bounds.size.height - LOCATIONBAR_HEIGHT;
self.addressLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelInset, locationBarY, self.view.bounds.size.width - labelInset, LOCATIONBAR_HEIGHT)];
self.addressLabel.adjustsFontSizeToFitWidth = NO;
self.addressLabel.alpha = 1.000;
self.addressLabel.autoresizesSubviews = YES;
@@ -463,23 +528,23 @@
self.addressLabel.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
self.addressLabel.enabled = YES;
self.addressLabel.hidden = NO;
self.addressLabel.lineBreakMode = UILineBreakModeTailTruncation;
self.addressLabel.minimumFontSize = 10.000;
self.addressLabel.lineBreakMode = NSLineBreakByTruncatingTail;
self.addressLabel.minimumScaleFactor = 10.000;
self.addressLabel.multipleTouchEnabled = NO;
self.addressLabel.numberOfLines = 1;
self.addressLabel.opaque = NO;
self.addressLabel.shadowOffset = CGSizeMake(0.0, -1.0);
self.addressLabel.text = @"Loading...";
self.addressLabel.textAlignment = UITextAlignmentLeft;
self.addressLabel.text = NSLocalizedString(@"Loading...", nil);
self.addressLabel.textAlignment = NSTextAlignmentLeft;
self.addressLabel.textColor = [UIColor colorWithWhite:1.000 alpha:1.000];
self.addressLabel.userInteractionEnabled = NO;
NSString* frontArrowString = @"►"; // create arrow from Unicode char
NSString* frontArrowString = NSLocalizedString(@"►", nil); // create arrow from Unicode char
self.forwardButton = [[UIBarButtonItem alloc] initWithTitle:frontArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goForward:)];
self.forwardButton.enabled = YES;
self.forwardButton.imageInsets = UIEdgeInsetsZero;
NSString* backArrowString = @"◄"; // create arrow from Unicode char
NSString* backArrowString = NSLocalizedString(@"◄", nil); // create arrow from Unicode char
self.backButton = [[UIBarButtonItem alloc] initWithTitle:backArrowString style:UIBarButtonItemStylePlain target:self action:@selector(goBack:)];
self.backButton.enabled = YES;
self.backButton.imageInsets = UIEdgeInsetsZero;
@@ -492,6 +557,11 @@
[self.view addSubview:self.spinner];
}
- (void) setWebViewFrame : (CGRect) frame {
NSLog(@"Setting the WebView's frame to %@", NSStringFromCGRect(frame));
[self.webView setFrame:frame];
}
- (void)setCloseButtonTitle:(NSString*)title
{
// the advantage of using UIBarButtonSystemItemDone is the system will localize it for you automatically
@@ -526,7 +596,7 @@
CGRect webViewBounds = self.view.bounds;
webViewBounds.size.height -= FOOTER_HEIGHT;
self.webView.frame = webViewBounds;
[self setWebViewFrame:webViewBounds];
locationbarFrame.origin.y = webViewBounds.size.height;
self.addressLabel.frame = locationbarFrame;
@@ -535,7 +605,7 @@
CGRect webViewBounds = self.view.bounds;
webViewBounds.size.height -= LOCATIONBAR_HEIGHT;
self.webView.frame = webViewBounds;
[self setWebViewFrame:webViewBounds];
locationbarFrame.origin.y = webViewBounds.size.height;
self.addressLabel.frame = locationbarFrame;
@@ -549,17 +619,15 @@
// webView take up whole height less toolBar height
CGRect webViewBounds = self.view.bounds;
webViewBounds.size.height -= TOOLBAR_HEIGHT;
self.webView.frame = webViewBounds;
[self setWebViewFrame:webViewBounds];
} else {
// no toolBar, expand webView to screen dimensions
CGRect webViewBounds = self.view.bounds;
self.webView.frame = webViewBounds;
[self setWebViewFrame:self.view.bounds];
}
}
}
- (void)showToolBar:(BOOL)show
- (void)showToolBar:(BOOL)show : (NSString *) toolbarPosition
{
CGRect toolbarFrame = self.toolbar.frame;
CGRect locationbarFrame = self.addressLabel.frame;
@@ -573,30 +641,31 @@
if (show) {
self.toolbar.hidden = NO;
CGRect webViewBounds = self.view.bounds;
if (locationbarVisible) {
// locationBar at the bottom, move locationBar up
// put toolBar at the bottom
CGRect webViewBounds = self.view.bounds;
webViewBounds.size.height -= FOOTER_HEIGHT;
self.webView.frame = webViewBounds;
locationbarFrame.origin.y = webViewBounds.size.height;
self.addressLabel.frame = locationbarFrame;
toolbarFrame.origin.y = (webViewBounds.size.height + LOCATIONBAR_HEIGHT);
self.toolbar.frame = toolbarFrame;
} else {
// no locationBar, so put toolBar at the bottom
CGRect webViewBounds = self.view.bounds;
webViewBounds.size.height -= TOOLBAR_HEIGHT;
self.webView.frame = webViewBounds;
toolbarFrame.origin.y = webViewBounds.size.height;
self.toolbar.frame = toolbarFrame;
}
if ([toolbarPosition isEqualToString:kInAppBrowserToolbarBarPositionTop]) {
toolbarFrame.origin.y = 0;
webViewBounds.origin.y += toolbarFrame.size.height;
[self setWebViewFrame:webViewBounds];
} else {
toolbarFrame.origin.y = (webViewBounds.size.height + LOCATIONBAR_HEIGHT);
}
[self setWebViewFrame:webViewBounds];
} else {
self.toolbar.hidden = YES;
@@ -607,16 +676,14 @@
// webView take up whole height less locationBar height
CGRect webViewBounds = self.view.bounds;
webViewBounds.size.height -= LOCATIONBAR_HEIGHT;
self.webView.frame = webViewBounds;
[self setWebViewFrame:webViewBounds];
// move locationBar down
locationbarFrame.origin.y = webViewBounds.size.height;
self.addressLabel.frame = locationbarFrame;
} else {
// no locationBar, expand webView to screen dimensions
CGRect webViewBounds = self.view.bounds;
self.webView.frame = webViewBounds;
[self setWebViewFrame:self.view.bounds];
}
}
}
@@ -632,22 +699,29 @@
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
[super viewDidUnload];
}
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleDefault;
}
- (void)close
{
[CDVUserAgentUtil releaseLock:&_userAgentLockToken];
if ([self respondsToSelector:@selector(presentingViewController)]) {
[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
} else {
[[self parentViewController] dismissModalViewControllerAnimated:YES];
}
self.currentURL = nil;
if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserExit)]) {
[self.navigationDelegate browserExit];
}
// Run later to avoid the "took a long time" log message.
dispatch_async(dispatch_get_main_queue(), ^{
if ([self respondsToSelector:@selector(presentingViewController)]) {
[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
} else {
[[self parentViewController] dismissModalViewControllerAnimated:YES];
}
});
}
- (void)navigateTo:(NSURL*)url
@@ -674,6 +748,34 @@
{
[self.webView goForward];
}
- (void)viewWillAppear:(BOOL)animated
{
if (IsAtLeastiOSVersion(@"7.0")) {
[[UIApplication sharedApplication] setStatusBarStyle:[self preferredStatusBarStyle]];
}
[self rePositionViews];
[super viewWillAppear:animated];
}
//
// On iOS 7 the status bar is part of the view's dimensions, therefore it's height has to be taken into account.
// The height of it could be hardcoded as 20 pixels, but that would assume that the upcoming releases of iOS won't
// change that value.
//
- (float) getStatusBarOffset {
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
float statusBarOffset = IsAtLeastiOSVersion(@"7.0") ? MIN(statusBarFrame.size.width, statusBarFrame.size.height) : 0.0;
return statusBarOffset;
}
- (void) rePositionViews {
if ([_browserOptions.toolbarposition isEqualToString:kInAppBrowserToolbarBarPositionTop]) {
[self.webView setFrame:CGRectMake(self.webView.frame.origin.x, TOOLBAR_HEIGHT, self.webView.frame.size.width, self.webView.frame.size.height)];
[self.toolbar setFrame:CGRectMake(self.toolbar.frame.origin.x, [self getStatusBarOffset], self.toolbar.frame.size.width, self.toolbar.frame.size.height)];
}
}
#pragma mark UIWebViewDelegate
@@ -681,7 +783,7 @@
{
// loading url, start spinner, update back/forward
self.addressLabel.text = @"Loading...";
self.addressLabel.text = NSLocalizedString(@"Loading...", nil);
self.backButton.enabled = theWebView.canGoBack;
self.forwardButton.enabled = theWebView.canGoForward;
@@ -732,13 +834,13 @@
- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
{
// log fail message, stop spinner, update back/forward
NSLog(@"webView:didFailLoadWithError - %@", [error localizedDescription]);
NSLog(@"webView:didFailLoadWithError - %i: %@", error.code, [error localizedDescription]);
self.backButton.enabled = theWebView.canGoBack;
self.forwardButton.enabled = theWebView.canGoForward;
[self.spinner stopAnimating];
self.addressLabel.text = @"Load Error";
self.addressLabel.text = NSLocalizedString(@"Load Error", nil);
[self.navigationDelegate webView:theWebView didFailLoadWithError:error];
}
@@ -782,6 +884,7 @@
self.location = YES;
self.toolbar = YES;
self.closebuttoncaption = nil;
self.toolbarposition = kInAppBrowserToolbarBarPositionBottom;
self.enableviewportscale = NO;
self.mediaplaybackrequiresuseraction = NO;
@@ -789,6 +892,7 @@
self.keyboarddisplayrequiresuseraction = YES;
self.suppressesincrementalrendering = NO;
self.hidden = NO;
self.disallowoverscroll = NO;
}
return self;

View File

@@ -0,0 +1,69 @@
/*
*
* Copyright 2013 Canonical Ltd.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
import QtQuick 2.0
import QtWebKit 3.0
import Ubuntu.Components.Popups 0.1
import Ubuntu.Components 0.1
Rectangle {
anchors.fill: parent
id: inappbrowser
property string url1
Rectangle {
border.color: "black"
width: parent.width
height: urlEntry.height
color: "gray"
TextInput {
id: urlEntry
width: parent.width - closeButton.width
text: url1
activeFocusOnPress: false
}
Image {
id: closeButton
width: height
x: parent.width - width
height: parent.height
source: "close.png"
MouseArea {
anchors.fill: parent
onClicked: {
root.exec("InAppBrowser", "close", [0, 0])
}
}
}
}
WebView {
width: parent.width
y: urlEntry.height
height: parent.height - y
url: url1
onLoadingChanged: {
if (loadRequest.status) {
root.exec("InAppBrowser", "loadFinished", [loadRequest.status])
}
}
}
}

BIN
src/ubuntu/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

106
src/ubuntu/inappbrowser.cpp Normal file
View File

@@ -0,0 +1,106 @@
/*
*
* Copyright 2013 Canonical Ltd.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include <QQuickView>
#include <QQuickItem>
#include "inappbrowser.h"
#include <cordova.h>
Inappbrowser::Inappbrowser(Cordova *cordova): CPlugin(cordova), _eventCb(0) {
}
const char code[] = "\
var component, object; \
function createObject() { \
component = Qt.createComponent(%1); \
if (component.status == Component.Ready) \
finishCreation(); \
else \
component.statusChanged.connect(finishCreation); \
} \
function finishCreation() { \
CordovaWrapper.object = component.createObject(root, \
{root: root, cordova: cordova, url1: %2}); \
} \
createObject()";
const char EXIT_EVENT[] = "'exit'";
const char LOADSTART_EVENT[] = "'loadstart'";
const char LOADSTOP_EVENT[] = "'loadstop'";
const char LOADERROR_EVENT[] = "'loaderror'";
void Inappbrowser::open(int cb, int, const QString &url, const QString &windowName, const QString &windowFeatures) {
assert(_eventCb == 0);
_eventCb = cb;
QString path = m_cordova->get_app_dir() + "/../qml/InAppBrowser.qml";
// TODO: relative url
QString qml = QString(code)
.arg(CordovaInternal::format(path)).arg(CordovaInternal::format(url));
m_cordova->execQML(qml);
}
void Inappbrowser::show(int, int) {
m_cordova->execQML("CordovaWrapper.object.visible = true");
}
void Inappbrowser::close(int, int) {
m_cordova->execQML("CordovaWrapper.object.destroy()");
this->callbackWithoutRemove(_eventCb, EXIT_EVENT);
_eventCb = 0;
}
void Inappbrowser::injectStyleFile(int cb, int, const QString&, bool) {
// TODO:
qCritical() << "unimplemented " << __PRETTY_FUNCTION__;
}
void Inappbrowser::injectStyleCode(int cb, int, const QString&, bool) {
// TODO:
qCritical() << "unimplemented " << __PRETTY_FUNCTION__;
}
void Inappbrowser::injectScriptFile(int cb, int, const QString&, bool) {
// TODO:
qCritical() << "unimplemented " << __PRETTY_FUNCTION__;
}
void Inappbrowser::injectScriptCode(int cb, int, const QString&, bool) {
// TODO:
qCritical() << "unimplemented " << __PRETTY_FUNCTION__;
}
void Inappbrowser::loadFinished(int status) {
if (status == 2) {
this->callbackWithoutRemove(_eventCb, LOADERROR_EVENT);
}
if (status == 0) {
this->callbackWithoutRemove(_eventCb, LOADSTART_EVENT);
}
if (status == 3) {
this->callbackWithoutRemove(_eventCb, LOADSTOP_EVENT);
}
}

61
src/ubuntu/inappbrowser.h Normal file
View File

@@ -0,0 +1,61 @@
/*
*
* Copyright 2013 Canonical Ltd.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#ifndef INAPPBROWSER_H
#define INAPPBROWSER_H
#include <QtCore>
#include <cplugin.h>
class Inappbrowser: public CPlugin {
Q_OBJECT
public:
Inappbrowser(Cordova *cordova);
virtual const QString fullName() override {
return Inappbrowser::fullID();
}
virtual const QString shortName() override {
return "InAppBrowser";
}
static const QString fullID() {
return "InAppBrowser";
}
public slots:
void open(int cb, int, const QString &url, const QString &windowName, const QString &windowFeatures);
void show(int, int);
void close(int, int);
void injectStyleFile(int cb, int, const QString&, bool);
void injectStyleCode(int cb, int, const QString&, bool);
void injectScriptFile(int cb, int, const QString&, bool);
void injectScriptCode(int cb, int, const QString&, bool);
void loadFinished(int status);
private:
int _eventCb;
};
#endif

View File

@@ -36,12 +36,45 @@ namespace WPCordovaClassLib.Cordova.Commands
private static ApplicationBarIconButton backButton;
private static ApplicationBarIconButton fwdButton;
protected ApplicationBar AppBar;
protected bool ShowLocation {get;set;}
protected bool StartHidden {get;set;}
public void open(string options)
{
// reset defaults on ShowLocation + StartHidden features
ShowLocation = true;
StartHidden = false;
string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
//BrowserOptions opts = JSON.JsonHelper.Deserialize<BrowserOptions>(options);
string urlLoc = args[0];
string target = args[1];
string featString = args[2];
string[] features = featString.Split(',');
foreach (string str in features)
{
try
{
string[] split = str.Split('=');
switch (split[0])
{
case "location":
ShowLocation = split[1].ToLower().StartsWith("yes");
break;
case "hidden":
StartHidden = split[1].ToLower().StartsWith("yes");
break;
}
}
catch(Exception)
{
// some sort of invalid param was passed, moving on ...
}
}
/*
_self - opens in the Cordova WebView if url is in the white-list, else it opens in the InAppBrowser
_blank - always open in the InAppBrowser
@@ -59,10 +92,99 @@ namespace WPCordovaClassLib.Cordova.Commands
ShowSystemBrowser(urlLoc);
break;
}
}
public void show(string options)
{
string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
if (browser != null)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
browser.Visibility = Visibility.Visible;
AppBar.IsVisible = true;
});
}
}
public void injectScriptCode(string options)
{
string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
bool bCallback = false;
if (bool.TryParse(args[1], out bCallback)) { };
string callbackId = args[2];
if (browser != null)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var res = browser.InvokeScript("eval", new string[] { args[0] });
if (bCallback)
{
PluginResult result = new PluginResult(PluginResult.Status.OK, res.ToString());
result.KeepCallback = false;
this.DispatchCommandResult(result);
}
});
}
}
public void injectScriptFile(string options)
{
Debug.WriteLine("Error : Windows Phone org.apache.cordova.inappbrowser does not currently support executeScript");
string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
// throw new NotImplementedException("Windows Phone does not currently support 'executeScript'");
}
public void injectStyleCode(string options)
{
Debug.WriteLine("Error : Windows Phone org.apache.cordova.inappbrowser does not currently support insertCSS");
return;
//string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
//bool bCallback = false;
//if (bool.TryParse(args[1], out bCallback)) { };
//string callbackId = args[2];
//if (browser != null)
//{
//Deployment.Current.Dispatcher.BeginInvoke(() =>
//{
// if (bCallback)
// {
// string cssInsertString = "try{(function(doc){var c = '<style>body{background-color:#ffff00;}</style>'; doc.head.innerHTML += c;})(document);}catch(ex){alert('oops : ' + ex.message);}";
// //cssInsertString = cssInsertString.Replace("_VALUE_", args[0]);
// Debug.WriteLine("cssInsertString = " + cssInsertString);
// var res = browser.InvokeScript("eval", new string[] { cssInsertString });
// if (bCallback)
// {
// PluginResult result = new PluginResult(PluginResult.Status.OK, res.ToString());
// result.KeepCallback = false;
// this.DispatchCommandResult(result);
// }
// }
//});
//}
}
public void injectStyleFile(string options)
{
Debug.WriteLine("Error : Windows Phone org.apache.cordova.inappbrowser does not currently support insertCSS");
return;
//string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
//throw new NotImplementedException("Windows Phone does not currently support 'insertCSS'");
}
private void ShowCordovaBrowser(string url)
{
Uri loc = new Uri(url, UriKind.RelativeOrAbsolute);
@@ -96,7 +218,7 @@ namespace WPCordovaClassLib.Cordova.Commands
private void ShowInAppBrowser(string url)
{
Uri loc = new Uri(url);
Uri loc = new Uri(url, UriKind.RelativeOrAbsolute);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
@@ -127,6 +249,12 @@ namespace WPCordovaClassLib.Cordova.Commands
browser.NavigationFailed += new System.Windows.Navigation.NavigationFailedEventHandler(browser_NavigationFailed);
browser.Navigated += new EventHandler<System.Windows.Navigation.NavigationEventArgs>(browser_Navigated);
browser.Navigate(loc);
if (StartHidden)
{
browser.Visibility = Visibility.Collapsed;
}
//browser.IsGeolocationEnabled = opts.isGeolocationEnabled;
grid.Children.Add(browser);
}
@@ -156,6 +284,9 @@ namespace WPCordovaClassLib.Cordova.Commands
bar.Buttons.Add(closeBtn);
page.ApplicationBar = bar;
bar.IsVisible = !StartHidden;
AppBar = bar;
}
}
@@ -251,7 +382,7 @@ namespace WPCordovaClassLib.Cordova.Commands
}
#endif
string message = "{\"type\":\"loadstop\", \"url\":\"" + e.Uri.AbsoluteUri + "\"}";
string message = "{\"type\":\"loadstop\", \"url\":\"" + e.Uri.OriginalString + "\"}";
PluginResult result = new PluginResult(PluginResult.Status.OK, message);
result.KeepCallback = true;
this.DispatchCommandResult(result);
@@ -259,7 +390,7 @@ namespace WPCordovaClassLib.Cordova.Commands
void browser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
{
string message = "{\"type\":\"error\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}";
string message = "{\"type\":\"error\",\"url\":\"" + e.Uri.OriginalString + "\"}";
PluginResult result = new PluginResult(PluginResult.Status.ERROR, message);
result.KeepCallback = true;
this.DispatchCommandResult(result);
@@ -267,7 +398,7 @@ namespace WPCordovaClassLib.Cordova.Commands
void browser_Navigating(object sender, NavigatingEventArgs e)
{
string message = "{\"type\":\"loadstart\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}";
string message = "{\"type\":\"loadstart\",\"url\":\"" + e.Uri.OriginalString + "\"}";
PluginResult result = new PluginResult(PluginResult.Status.OK, message);
result.KeepCallback = true;
this.DispatchCommandResult(result);

BIN
test/.DS_Store vendored

Binary file not shown.

70
test/cordova-incl.js vendored
View File

@@ -1,70 +0,0 @@
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
var PLAT;
if (/Android/.exec(navigator.userAgent)) {
PLAT = 'android';
} else if (/(iPad)|(iPhone)|(iPod)/.exec(navigator.userAgent)) {
PLAT = 'ios';
} else if (/(BB10)|(PlayBook)|(BlackBerry)/.exec(navigator.userAgent)) {
PLAT = 'blackberry';
}
var scripts = document.getElementsByTagName('script');
var currentPath = scripts[scripts.length - 1].src;
var platformCordovaPath = currentPath.replace("cordova-incl.js", "cordova." + PLAT + ".js");
var normalCordovaPath = currentPath.replace("cordova-incl.js", "cordova.js");
var cordovaPath = normalCordovaPath;
if (PLAT) {
// XHR to local file is an error on some platforms, windowsphone for one
try {
var xhr = new XMLHttpRequest();
xhr.open("GET", platformCordovaPath, false);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE && this.responseText.length > 0) {
if(parseInt(this.status) >= 400){
cordovaPath = normalCordovaPath;
}else{
cordovaPath = platformCordovaPath;
}
}
};
xhr.send(null);
}
catch(e){
cordovaPath = normalCordovaPath;
} // access denied!
}
if (!window._doNotWriteCordovaScript) {
document.write('<script type="text/javascript" charset="utf-8" src="' + cordovaPath + '"></script>');
}
function backHome() {
if (window.device && device.platform && device.platform.toLowerCase() == 'android') {
navigator.app.backHistory();
}
else {
window.history.go(-1);
}
}

View File

@@ -1,258 +0,0 @@
<!DOCTYPE html>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
<title>Cordova Mobile Spec</title>
<link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<script type="text/javascript" charset="utf-8" src="../cordova-incl.js"></script>
<script type="text/javascript" charset="utf-8">
var deviceReady = false;
/**
* Function called when page has finished loading.
*/
function init() {
document.addEventListener("deviceready", function() {
deviceReady = true;
console.log("Device="+device.platform+" "+device.version);
}, false);
function updateUserAgent() {
document.getElementById("user-agent").textContent = navigator.userAgent;
}
updateUserAgent();
window.setInterval(updateUserAgent, 1500);
window.setTimeout(function() {
if (!deviceReady) {
alert("Error: Apache Cordova did not initialize. Demo will not run correctly.");
}
},1000);
}
function doOpen(url, target, params, numExpectedRedirects) {
numExpectedRedirects = numExpectedRedirects || 0;
var iab = window.open(url, target, params);
if (!iab) {
alert('window.open returned ' + iab);
return;
}
var counts;
var lastLoadStartURL;
var wasReset = false;
function reset() {
counts = {
'loaderror': 0,
'loadstart': 0,
'loadstop': 0,
'exit': 0
};
lastLoadStartURL = '';
}
reset();
function logEvent(e) {
console.log('IAB event=' + JSON.stringify(e));
counts[e.type]++;
// Verify that event.url gets updated on redirects.
if (e.type == 'loadstart') {
if (e.url == lastLoadStartURL) {
alert('Unexpected: loadstart fired multiple times for the same URL.');
}
lastLoadStartURL = e.url;
}
// Verify the right number of loadstart events were fired.
if (e.type == 'loadstop' || e.type == 'loaderror') {
if (e.url != lastLoadStartURL) {
alert('Unexpected: ' + e.type + ' event.url != loadstart\'s event.url');
}
if (numExpectedRedirects === 0 && counts['loadstart'] !== 1) {
// Do allow a loaderror without a loadstart (e.g. in the case of an invalid URL).
if (!(e.type == 'loaderror' && counts['loadstart'] === 0)) {
alert('Unexpected: got multiple loadstart events. (' + counts['loadstart'] + ')');
}
} else if (numExpectedRedirects > 0 && counts['loadstart'] < (numExpectedRedirects+1)) {
alert('Unexpected: should have got at least ' + (numExpectedRedirects+1) + ' loadstart events, but got ' + counts['loadstart']);
}
wasReset = true;
numExpectedRedirects = 0;
reset();
}
// Verify that loadend / loaderror was called.
if (e.type == 'exit') {
var numStopEvents = counts['loadstop'] + counts['loaderror'];
if (numStopEvents === 0 && !wasReset) {
alert('Unexpected: browser closed without a loadstop or loaderror.')
} else if (numStopEvents > 1) {
alert('Unexpected: got multiple loadstop/loaderror events.');
}
}
}
iab.addEventListener('loaderror', logEvent, false);
iab.addEventListener('loadstart', logEvent, false);
iab.addEventListener('loadstop', logEvent, false);
iab.addEventListener('exit', logEvent, false);
return iab;
}
function openWithStyle(url, cssUrl, useCallback) {
var iab = doOpen(url, '_blank', 'location=yes');
var callback = function(results) {
if (results && results.length === 0) {
alert('Results verified');
} else {
console.log(results);
alert('Got: ' + typeof(results) + '\n' + JSON.stringify(results));
}
};
if (cssUrl) {
iab.addEventListener('loadstop', function(event) {
iab.insertCSS({file: cssUrl}, useCallback && callback);
});
} else {
iab.addEventListener('loadstop', function(event) {
iab.insertCSS({code:'#style-update-literal { \ndisplay: block !important; \n}'},
useCallback && callback);
});
}
}
function openWithScript(url, jsUrl, useCallback) {
var iab = doOpen(url, '_blank', 'location=yes');
if (jsUrl) {
iab.addEventListener('loadstop', function(event) {
iab.executeScript({file: jsUrl}, useCallback && function(results) {
if (results && results.length === 0) {
alert('Results verified');
} else {
console.log(results);
alert('Got: ' + typeof(results) + '\n' + JSON.stringify(results));
}
});
});
} else {
iab.addEventListener('loadstop', function(event) {
var code = '(function(){\n' +
' var header = document.getElementById("header");\n' +
' header.innerHTML = "Script literal successfully injected";\n' +
' return "abc";\n' +
'})()';
iab.executeScript({code:code}, useCallback && function(results) {
if (results && results.length === 1 && results[0] === 'abc') {
alert('Results verified');
} else {
console.log(results);
alert('Got: ' + typeof(results) + '\n' + JSON.stringify(results));
}
});
});
}
}
var hiddenwnd=null;
var loadlistener = function(event) { alert('background window loaded ' ); };
function openHidden(url, startHidden) {
var shopt =(startHidden) ? 'hidden=yes' : '';
hiddenwnd = window.open(url,'random_string',shopt);
if (!hiddenwnd) {
alert('window.open returned ' + hiddenwnd);
return;
}
if(startHidden) hiddenwnd.addEventListener('loadstop', loadlistener);
}
function showHidden() {
if(!!hiddenwnd ) {
hiddenwnd.show();
}
}
function closeHidden() {
if(!!hiddenwnd ) {
hiddenwnd.removeEventListener('loadstop',loadlistener);
hiddenwnd.close();
hiddenwnd=null;
}
}
</script>
</head>
<body onload="init();" id="stage" class="theme">
<h1>InAppBrowser</h1>
<div id="info">
Make sure http://www.google.com is white listed. </br>
Make sure http://www.apple.com is not in the white list.</br> In iOS, starred <span style="vertical-align:super">*</span> tests will leave the app with no way to return. </br>
<h4>User-Agent: <span id="user-agent"> </span></h4>
</div>
<div onclick="backHome();">Back</div>
<h1>Local URL</h1>
<div class="btn large" onclick="doOpen('local.html');">Default: CordovaWebView</div>
<div class="btn large" onclick="doOpen('local.html', '_self');">Target=Self: CordovaWebView</div>
<div class="btn large" onclick="doOpen('local.html', '_system');">Target=System: Error</div>
<div class="btn large" onclick="doOpen('local.html', '_blank');">Target=Blank: InAppBrowser</div>
<div class="btn large" onclick="doOpen('local.html', 'random_string');">Target=Random: InAppBrowser</div>
<div class="btn large" onclick="doOpen('local.html', 'random_string', 'location=no');">Target=Random, no location bar: InAppBrowser</div>
<h1>White Listed URL</h1>
<div class="btn large" onclick="doOpen('http://www.google.com');">Default: CordovaWebView<span style="vertical-align:super">*</span></div>
<div class="btn large" onclick="doOpen('http://www.google.com', '_self');">Target=Self: CordovaWebView<span style="vertical-align:super">*</span></div>
<div class="btn large" onclick="doOpen('http://www.google.com', '_system');">Target=System: System Browser</div>
<div class="btn large" onclick="doOpen('http://www.google.com', '_blank');">Target=Blank: InAppBrowser</div>
<div class="btn large" onclick="doOpen('http://www.google.com', 'random_string');">Target=Random: InAppBrowser</div>
<div class="btn large" onclick="doOpen('http://www.google.com', 'random_string', 'location=no');">Target=Random, no location bar: InAppBrowser</div>
<h1>Non White Listed URL</h1>
<div class="btn large" onclick="doOpen('http://www.apple.com');">Default: InAppBrowser</div>
<div class="btn large" onclick="doOpen('http://www.apple.com', '_self');">Target=Self: InAppBrowser</div>
<div class="btn large" onclick="doOpen('http://www.apple.com', '_system');">Target=System: System</div>
<div class="btn large" onclick="doOpen('http://www.apple.com', '_blank');">Target=Blank: InAppBrowser</div>
<div class="btn large" onclick="doOpen('http://www.apple.com', 'random_string');">Target=Random: InAppBrowser</div>
<div class="btn large" onclick="doOpen('http://www.apple.com', 'random_string', 'location=no');">Target=Random, no location bar: InAppBrowser</div>
<h1>Page with redirect</h1>
<div class="btn large" onclick="doOpen('http://google.com', 'random_string', '', 1);">http://google.com (should 301)</div>
<div class="btn large" onclick="doOpen('http://goo.gl/pUFqg', 'random_string', '', 2);">http://www.zhihu.com/answer/16714076 (should 302)</div>
<h1>PDF URL</h1>
<div class="btn large" onclick="doOpen('http://www.stluciadance.com/prospectus_file/sample.pdf');">Remote URL</div>
<div class="btn large" onclick="doOpen('local.pdf', '_blank');">Local URL</div>
<h1>INVALID URL</h1>
<div class="btn large" onclick="doOpen('x-ttp://www.invalid.com/', '_blank');">Invalid Scheme</div>
<div class="btn large" onclick="doOpen('http://www.inv;alid.com/', '_blank');">Invalid Host</div>
<div class="btn large" onclick="doOpen('nonexistent.html', '_blank');">Missing File</div>
<h1>CSS / JS Injection</h1>
<div class="btn large" onclick="doOpen('inject.html', '_blank');">Original Document</div>
<div class="btn large" onclick="openWithStyle('inject.html','inject.css');">CSS File Injection</div>
<div class="btn large" onclick="openWithStyle('inject.html','inject.css', true);">CSS File Injection (CB)</div>
<div class="btn large" onclick="openWithStyle('inject.html');">CSS Literal Injection</div>
<div class="btn large" onclick="openWithStyle('inject.html', null, true);">CSS Literal Injection (CB)</div>
<div class="btn large" onclick="openWithScript('inject.html', 'inject.js');">Script File Injection</div>
<div class="btn large" onclick="openWithScript('inject.html', 'inject.js', true);">Script File Injection (CB)</div>
<div class="btn large" onclick="openWithScript('inject.html');">Script Literal Injection</div>
<div class="btn large" onclick="openWithScript('inject.html', null, true);">Script Literal Injection (CB)</div>
<h1>Open Hidden </h1>
<div class="btn large" onclick="openHidden('http://google.com',true);">google.com hidden</div>
<div class="btn large" onclick="showHidden();">show hidden</div>
<div class="btn large" onclick="closeHidden();">close hidden</div>
<div class="btn large" onclick="openHidden('http://google.com',false);">google.com not hidden</div>
<h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
</body>
</html>

View File

@@ -1,21 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#style-update-file {
display: block !important;
}

View File

@@ -1,43 +0,0 @@
<!DOCTYPE html>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
<title>Cordova Mobile Spec</title>
<link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
</head>
<body id="stage" class="theme">
<h1 id="header">InAppBrowser - Script / Style Injection Test</h1>
<h2 id="style-update-file" style="display:none">Style updated from file</h2>
<h2 id="style-update-literal" style="display:none">Style updated from literal</h2>
</body>
<script>
function updateUserAgent() {
document.getElementById("u-a").textContent = navigator.userAgent;
}
updateUserAgent();
window.setInterval(updateUserAgent, 1500);
</script>
</html>

View File

@@ -1,20 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var d = document.getElementById("header")
d.innerHTML = "Script file successfully injected";

View File

@@ -1,51 +0,0 @@
<!DOCTYPE html>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
<title>Cordova Mobile Spec</title>
<link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<script type="text/javascript" charset="utf-8" src="../cordova-incl.js"></script>
</head>
<body id="stage" class="theme">
<h1>InAppBrowser - Local URL</h1>
<div id="info">
You have successfully loaded a local URL
</div>
<div>User-Agent = <span id="u-a"></span></div>
<div><a href="http://www.google.com">Visit Google</a></div>
<div><a href="http://www.yahoo.com">Visit Yahoo</a></div>
<div><a href="http://www.stluciadance.com/prospectus_file/sample.pdf">Check out my remote PDF</a></div>
<div><a href="local.pdf">Check out my local PDF</a></div>
<h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
</body>
<script>
function updateUserAgent() {
document.getElementById("u-a").textContent = navigator.userAgent;
}
updateUserAgent();
window.setInterval(updateUserAgent, 1500);
</script>
</html>

Binary file not shown.

View File

@@ -1,65 +0,0 @@
<!DOCTYPE html>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,initial-scale=1.0" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Cordova Mobile Spec</title>
<link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
<script type="text/javascript" charset="utf-8" src="cordova-incl.js"></script>
<script type="text/javascript" charset="utf-8" src="main.js"></script>
</head>
<body onload="init();" id="stage" class="theme">
<h1>Apache Cordova Tests</h1>
<div id="info">
<h4>Platform: <span id="platform"> </span></h4>
<h4>Version: <span id="version"> </span></h4>
<h4>UUID: <span id="uuid"> </span></h4>
<h4>Name: <span id="name"> </span></h4>
<h4>Model: <span id="model"> </span></h4>
<h4>Width: <span id="width"> </span>, Height: <span id="height">
</span>, Color Depth: <span id="colorDepth"></span></h4>
<h4>User-Agent: <span id="user-agent"> </span></h4>
</div>
<a href="autotest/index.html" class="btn large">Automatic Test</a>
<a href="accelerometer/index.html" class="btn large">Accelerometer</a>
<a href="audio/index.html" class="btn large">Audio Play/Record</a>
<a href="battery/index.html" class="btn large">Battery</a>
<a href="camera/index.html" class="btn large">Camera</a>
<a href="compass/index.html" class="btn large">Compass</a>
<a href="contacts/index.html" class="btn large">Contacts</a>
<a href="events/index.html" class="btn large">Events</a>
<a href="location/index.html" class="btn large">Location</a>
<a href="lazyloadjs/index.html" class="btn large">Lazy Loading of cordova-incl.js</a>
<a href="misc/index.html" class="btn large">Misc Content</a>
<a href="network/index.html" class="btn large">Network</a>
<a href="notification/index.html" class="btn large">Notification</a>
<a href="splashscreen/index.html" class="btn large">Splashscreen</a>
<a href="sql/index.html" class="btn large">Web SQL</a>
<a href="storage/index.html" class="btn large">Local Storage</a>
<a href="benchmarks/index.html" class="btn large">Benchmarks</a>
<a href="inappbrowser/index.html" class="btn large">In App Browser</a>
</body>
</html>

View File

@@ -1,163 +0,0 @@
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
var deviceInfo = function() {
document.getElementById("platform").innerHTML = device.platform;
document.getElementById("version").innerHTML = device.version;
document.getElementById("uuid").innerHTML = device.uuid;
document.getElementById("name").innerHTML = device.name;
document.getElementById("model").innerHTML = device.model;
document.getElementById("width").innerHTML = screen.width;
document.getElementById("height").innerHTML = screen.height;
document.getElementById("colorDepth").innerHTML = screen.colorDepth;
};
var getLocation = function() {
var suc = function(p) {
alert(p.coords.latitude + " " + p.coords.longitude);
};
var locFail = function() {
};
navigator.geolocation.getCurrentPosition(suc, locFail);
};
var beep = function() {
navigator.notification.beep(2);
};
var vibrate = function() {
navigator.notification.vibrate(0);
};
function roundNumber(num) {
var dec = 3;
var result = Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
return result;
}
var accelerationWatch = null;
function updateAcceleration(a) {
document.getElementById('x').innerHTML = roundNumber(a.x);
document.getElementById('y').innerHTML = roundNumber(a.y);
document.getElementById('z').innerHTML = roundNumber(a.z);
}
var toggleAccel = function() {
if (accelerationWatch !== null) {
navigator.accelerometer.clearWatch(accelerationWatch);
updateAcceleration({
x : "",
y : "",
z : ""
});
accelerationWatch = null;
} else {
var options = {};
options.frequency = 1000;
accelerationWatch = navigator.accelerometer.watchAcceleration(
updateAcceleration, function(ex) {
alert("accel fail (" + ex.name + ": " + ex.message + ")");
}, options);
}
};
var preventBehavior = function(e) {
e.preventDefault();
};
function dump_pic(data) {
var viewport = document.getElementById('viewport');
console.log(data);
viewport.style.display = "";
viewport.style.position = "absolute";
viewport.style.top = "10px";
viewport.style.left = "10px";
document.getElementById("test_img").src = "data:image/jpeg;base64," + data;
}
function fail(msg) {
alert(msg);
}
function show_pic() {
navigator.camera.getPicture(dump_pic, fail, {
quality : 50
});
}
function close() {
var viewport = document.getElementById('viewport');
viewport.style.position = "relative";
viewport.style.display = "none";
}
// This is just to do this.
function readFile() {
navigator.file.read('/sdcard/cordova.txt', fail, fail);
}
function writeFile() {
navigator.file.write('foo.txt', "This is a test of writing to a file",
fail, fail);
}
function contacts_success(contacts) {
alert(contacts.length
+ ' contacts returned.'
+ (contacts[2] && contacts[2].name ? (' Third contact is ' + contacts[2].name.formatted)
: ''));
}
function get_contacts() {
var obj = new ContactFindOptions();
obj.filter = "";
obj.multiple = true;
obj.limit = 5;
navigator.service.contacts.find(
[ "displayName", "name" ], contacts_success,
fail, obj);
}
var networkReachableCallback = function(reachability) {
// There is no consistency on the format of reachability
var networkState = reachability.code || reachability;
var currentState = {};
currentState[NetworkStatus.NOT_REACHABLE] = 'No network connection';
currentState[NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK] = 'Carrier data connection';
currentState[NetworkStatus.REACHABLE_VIA_WIFI_NETWORK] = 'WiFi connection';
confirm("Connection type:\n" + currentState[networkState]);
};
function check_network() {
navigator.network.isReachable("www.mobiledevelopersolutions.com",
networkReachableCallback, {});
}
function init() {
// the next line makes it impossible to see Contacts on the HTC Evo since it
// doesn't have a scroll button
// document.addEventListener("touchmove", preventBehavior, false);
document.addEventListener("deviceready", deviceInfo, true);
document.getElementById("user-agent").textContent = navigator.userAgent;
}

View File

@@ -1,164 +0,0 @@
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
body {
background:#222 none repeat scroll 0 0;
color:#666;
font-family:Helvetica;
font-size:72%;
line-height:1.5em;
margin:0;
border-top:1px solid #393939;
}
#info{
background:#ffa;
border: 1px solid #ffd324;
-webkit-border-radius: 5px;
border-radius: 5px;
clear:both;
margin:15px 6px 0;
min-width:295px;
max-width:97%;
padding:4px 0px 2px 10px;
word-wrap:break-word;
margin-bottom:10px;
display:inline-block;
min-height: 160px;
max-height: 300px;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
#info > h4{
font-size:.95em;
margin:5px 0;
}
#stage.theme{
padding-top:3px;
}
/* Definition List */
#stage.theme > dl{
padding-top:10px;
clear:both;
margin:0;
list-style-type:none;
padding-left:10px;
overflow:auto;
}
#stage.theme > dl > dt{
font-weight:bold;
float:left;
margin-left:5px;
}
#stage.theme > dl > dd{
width:45px;
float:left;
color:#a87;
font-weight:bold;
}
/* Content Styling */
#stage.theme > h1, #stage.theme > h2, #stage.theme > p{
margin:1em 0 .5em 13px;
}
#stage.theme > h1{
color:#eee;
font-size:1.6em;
text-align:center;
margin:0;
margin-top:15px;
padding:0;
}
#stage.theme > h2{
clear:both;
margin:0;
padding:3px;
font-size:1em;
text-align:center;
}
/* Stage Buttons */
#stage.theme .btn{
border: 1px solid #555;
-webkit-border-radius: 5px;
border-radius: 5px;
text-align:center;
display:inline-block;
background:#444;
width:150px;
color:#9ab;
font-size:1.1em;
text-decoration:none;
padding:1.2em 0;
margin:3px 0px 3px 5px;
}
#stage.theme .large{
width:308px;
padding:1.2em 0;
}
#stage.theme .wide{
width:100%;
padding:1.2em 0;
}
#stage.theme .backBtn{
border: 1px solid #555;
-webkit-border-radius: 5px;
border-radius: 5px;
text-align:center;
display:block;
float:right;
background:#666;
width:75px;
color:#9ab;
font-size:1.1em;
text-decoration:none;
padding:1.2em 0;
margin:3px 5px 3px 5px;
}
#stage.theme .input{
border: 1px solid #555;
-webkit-border-radius: 5px;
border-radius: 5px;
text-align:center;
display:block;
float:light;
background:#888;
color:#9cd;
font-size:1.1em;
text-decoration:none;
padding:1.2em 0;
margin:3px 0px 3px 5px;
}
#stage.theme .numeric{
width:100%;
}

View File

@@ -22,6 +22,7 @@
var exec = require('cordova/exec');
var channel = require('cordova/channel');
var modulemapper = require('cordova/modulemapper');
var urlutil = require('cordova/urlutil');
function InAppBrowser() {
this.channels = {
@@ -77,17 +78,18 @@ InAppBrowser.prototype = {
};
module.exports = function(strUrl, strWindowName, strWindowFeatures) {
var iab = new InAppBrowser();
var cb = function(eventname) {
iab._eventHandler(eventname);
};
// Don't catch calls that write to existing frames (e.g. named iframes).
if (window.frames && window.frames[strWindowName]) {
var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
return origOpenFunc.apply(window, arguments);
}
strUrl = urlutil.makeAbsolute(strUrl);
var iab = new InAppBrowser();
var cb = function(eventname) {
iab._eventHandler(eventname);
};
exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
return iab;
};

View File

@@ -1,4 +1,4 @@
cordova.define("org.apache.cordova.inappbrowser.InAppBrowserProxy", function(require, exports, module) { /*
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -19,7 +19,8 @@ cordova.define("org.apache.cordova.inappbrowser.InAppBrowserProxy", function(req
*
*/
/*global Windows:true */
/*jslint sloppy:true */
/*global Windows:true, require, document, setTimeout, window, module */
@@ -30,27 +31,29 @@ var browserWrap;
var IAB = {
close: function (win,lose) {
close: function (win, lose) {
if (browserWrap) {
browserWrap.parentNode.removeChild(browserWrap);
browserWrap = null;
}
},
show: function (win,lose) {
show: function (win, lose) {
/* empty block, ran out of bacon?
if (browserWrap) {
}
}*/
},
open: function (win,lose,args) {
var strUrl = args[0];
var target = args[1];
var features = args[2];
open: function (win, lose, args) {
var strUrl = args[0],
target = args[1],
features = args[2],
url,
elem;
if (target == "_system") {
var url = new Windows.Foundation.Uri(strUrl)
if (target === "_system") {
url = new Windows.Foundation.Uri(strUrl);
Windows.System.Launcher.launchUriAsync(url);
}
else if (target == "_blank") {
} else if (target === "_blank") {
if (!browserWrap) {
browserWrap = document.createElement("div");
browserWrap.style.position = "absolute";
@@ -64,28 +67,27 @@ var IAB = {
setTimeout(function () {
IAB.close();
}, 0);
}
};
document.body.appendChild(browserWrap);
}
var elem = document.createElement("iframe");
elem.style.width = (window.innerWidth - 80)+ "px";
elem.style.height = (window.innerHeight - 80) + "px";
elem.style.borderWidth = "0px";
elem.name = "targetFrame";
elem.src = strUrl;
elem = document.createElement("iframe");
elem.style.width = (window.innerWidth - 80) + "px";
elem.style.height = (window.innerHeight - 80) + "px";
elem.style.borderWidth = "0px";
elem.name = "targetFrame";
elem.src = strUrl;
window.addEventListener("resize", function () {
if (browserWrap && elem) {
elem.style.width = (window.innerWidth - 80) + "px";
elem.style.height = (window.innerHeight - 80) + "px";
}
});
window.addEventListener("resize", function () {
if (browserWrap && elem) {
elem.style.width = (window.innerWidth - 80) + "px";
elem.style.height = (window.innerHeight - 80) + "px";
}
});
browserWrap.appendChild(elem);
}
else {
} else {
window.location = strUrl;
}
@@ -93,12 +95,12 @@ var IAB = {
},
injectScriptCode:function(code, bCB) {
injectScriptCode: function (code, bCB) {
// "(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)"
},
injectScriptFile:function(file, bCB) {
injectScriptFile: function (file, bCB) {
}
};
@@ -106,4 +108,4 @@ var IAB = {
module.exports = IAB;
require("cordova/windows8/commandProxy").add("InAppBrowser",module.exports);
require("cordova/windows8/commandProxy").add("InAppBrowser", module.exports);