[
https://issues.apache.org/jira/browse/CB-14188?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16637578#comment-16637578
]
ASF GitHub Bot commented on CB-14188:
-------------------------------------
brodybits closed pull request #276: CB-14188: Add beforeload event, catching
navigation before it happens
URL: https://github.com/apache/cordova-plugin-inappbrowser/pull/276
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/README.md b/README.md
index eade58a37..9aa1a4382 100644
--- a/README.md
+++ b/README.md
@@ -115,6 +115,7 @@ instance, or the system browser.
Android supports these additional options:
- __hidden__: set to `yes` to create the browser and load the page, but
not show it. The loadstop event fires when loading is complete. Omit or set to
`no` (default) to have the browser open and load normally.
+ - __beforeload__: set to `yes` to enable the `beforeload` event to modify
which pages are actually loaded in the browser.
- __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
- __closebuttoncaption__: set to a string to use as the close button's
caption instead of a X. Note that you need to localize this value yourself.
@@ -137,6 +138,7 @@ instance, or the system browser.
iOS supports these additional options:
- __hidden__: set to `yes` to create the browser and load the page, but
not show it. The loadstop event fires when loading is complete. Omit or set to
`no` (default) to have the browser open and load normally.
+ - __beforeload__: set to `yes` to enable the `beforeload` event to modify
which pages are actually loaded in the browser.
- __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
- __closebuttoncolor__: set as a valid hex color string, for example:
`#00ff00`, to change from the default __Done__ button's color. Only applicable
if toolbar is not disabled.
@@ -217,6 +219,7 @@ The object returned from a call to
`cordova.InAppBrowser.open` when the target i
- __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.
+ - __beforeload__: event fires when the `InAppBrowser` decides whether to
load an URL or not (only with option `beforeload=yes`).
- __callback__: the function that executes when the event fires. The function
is passed an `InAppBrowserEvent` object as a parameter.
@@ -230,7 +233,7 @@ function showHelp(url) {
var target = "_blank";
- var options = "location=yes,hidden=yes";
+ var options = "location=yes,hidden=yes,beforeload=yes";
inAppBrowserRef = cordova.InAppBrowser.open(url, target, options);
@@ -240,6 +243,8 @@ function showHelp(url) {
inAppBrowserRef.addEventListener('loaderror', loadErrorCallBack);
+ inAppBrowserRef.addEventListener('beforeload', beforeloadCallBack);
+
}
function loadStartCallBack() {
@@ -288,6 +293,20 @@ function executeScriptCallBack(params) {
}
+function beforeloadCallback(params, callback) {
+
+ if (params.url.startsWith("http://www.example.com/")) {
+
+ // Load this URL in the inAppBrowser.
+ callback(params.url);
+ } else {
+
+ // The callback is not invoked, so the page will not be loaded.
+ $('#status-message').text("This browser only opens pages on
http://www.example.com/");
+ }
+
+}
+
```
### InAppBrowserEvent Properties
diff --git a/src/android/InAppBrowser.java b/src/android/InAppBrowser.java
index 92ca3c1a1..93d946089 100644
--- a/src/android/InAppBrowser.java
+++ b/src/android/InAppBrowser.java
@@ -110,6 +110,7 @@ Licensed to the Apache Software Foundation (ASF) under one
private static final String HIDE_URL = "hideurlbar";
private static final String FOOTER = "footer";
private static final String FOOTER_COLOR = "footercolor";
+ private static final String BEFORELOAD = "beforeload";
private static final List customizableOptions =
Arrays.asList(CLOSE_BUTTON_CAPTION, TOOLBAR_COLOR, NAVIGATION_COLOR,
CLOSE_BUTTON_COLOR, FOOTER_COLOR);
@@ -138,6 +139,7 @@ Licensed to the Apache Software Foundation (ASF) under one
private boolean hideUrlBar = false;
private boolean showFooter = false;
private String footerColor = "";
+ private boolean useBeforeload = false;
private String[] allowedSchemes;
/**
@@ -246,6 +248,20 @@ else if (SYSTEM.equals(target)) {
else if (action.equals("close")) {
closeDialog();
}
+ else if (action.equals("loadAfterBeforeload")) {
+ if (!useBeforeload) {
+ LOG.e(LOG_TAG, "unexpected loadAfterBeforeload called without
feature beforeload=yes");
+ }
+ final String url = args.getString(0);
+ this.cordova.getActivity().runOnUiThread(new Runnable() {
+ @SuppressLint("NewApi")
+ @Override
+ public void run() {
+
((InAppBrowserClient)inAppWebView.getWebViewClient()).waitForBeforeload = false;
+ inAppWebView.loadUrl(url);
+ }
+ });
+ }
else if (action.equals("injectScriptCode")) {
String jsWrapper = null;
if (args.getBoolean(1)) {
@@ -674,6 +690,10 @@ public String showWebPage(final String url,
HashMap<String, String> features) {
if (footerColorSet != null) {
footerColor = footerColorSet;
}
+ String beforeload = features.get(BEFORELOAD);
+ if (beforeload != null) {
+ useBeforeload = beforeload.equals("yes") ? true : false;
+ }
}
final CordovaWebView thatWebView = this.webView;
@@ -924,7 +944,7 @@ public void openFileChooser(ValueCallback<Uri> uploadMsg,
String acceptType)
}
});
- WebViewClient client = new InAppBrowserClient(thatWebView,
edittext);
+ WebViewClient client = new InAppBrowserClient(thatWebView,
edittext, useBeforeload);
inAppWebView.setWebViewClient(client);
WebSettings settings = inAppWebView.getSettings();
settings.setJavaScriptEnabled(true);
@@ -1085,6 +1105,8 @@ public void onActivityResult(int requestCode, int
resultCode, Intent intent) {
public class InAppBrowserClient extends WebViewClient {
EditText edittext;
CordovaWebView webView;
+ boolean useBeforeload;
+ boolean waitForBeforeload;
/**
* Constructor.
@@ -1092,9 +1114,11 @@ public void onActivityResult(int requestCode, int
resultCode, Intent intent) {
* @param webView
* @param mEditText
*/
- public InAppBrowserClient(CordovaWebView webView, EditText mEditText) {
+ public InAppBrowserClient(CordovaWebView webView, EditText mEditText,
boolean useBeforeload) {
this.webView = webView;
this.edittext = mEditText;
+ this.useBeforeload = useBeforeload;
+ this.waitForBeforeload = useBeforeload;
}
/**
@@ -1107,12 +1131,27 @@ public InAppBrowserClient(CordovaWebView webView,
EditText mEditText) {
*/
@Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
+ boolean override = false;
+
+ // On first URL change, initiate JS callback. Only after the
beforeload event, continue.
+ if (this.waitForBeforeload) {
+ try {
+ JSONObject obj = new JSONObject();
+ obj.put("type", "beforeload");
+ obj.put("url", url);
+ sendUpdate(obj, true);
+ return true;
+ } catch (JSONException ex) {
+ LOG.e(LOG_TAG, "URI passed in has caused a JSON error.");
+ }
+ }
+
if (url.startsWith(WebView.SCHEME_TEL)) {
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
cordova.getActivity().startActivity(intent);
- return true;
+ override = true;
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error dialing " + url + ": " +
e.toString());
}
@@ -1121,7 +1160,7 @@ public boolean shouldOverrideUrlLoading(WebView webView,
String url) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
cordova.getActivity().startActivity(intent);
- return true;
+ override = true;
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString());
}
@@ -1152,7 +1191,7 @@ else if (url.startsWith("sms:")) {
intent.putExtra("address", address);
intent.setType("vnd.android-dir/mms-sms");
cordova.getActivity().startActivity(intent);
- return true;
+ override = true;
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error sending sms " + url + ":" +
e.toString());
}
@@ -1173,7 +1212,7 @@ else if (!url.startsWith("http:") &&
!url.startsWith("https:") && url.matches("^
obj.put("type", "customscheme");
obj.put("url", url);
sendUpdate(obj, true);
- return true;
+ override = true;
} catch (JSONException ex) {
LOG.e(LOG_TAG, "Custom Scheme URI passed in
has caused a JSON error.");
}
@@ -1182,7 +1221,10 @@ else if (!url.startsWith("http:") &&
!url.startsWith("https:") && url.matches("^
}
}
- return false;
+ if (this.useBeforeload) {
+ this.waitForBeforeload = true;
+ }
+ return override;
}
@@ -1304,4 +1346,4 @@ public void onReceivedHttpAuthRequest(WebView view,
HttpAuthHandler handler, Str
super.onReceivedHttpAuthRequest(view, handler, host, realm);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ios/CDVInAppBrowser.h b/src/ios/CDVInAppBrowser.h
index 66066b9ba..e415f40b8 100644
--- a/src/ios/CDVInAppBrowser.h
+++ b/src/ios/CDVInAppBrowser.h
@@ -30,7 +30,11 @@
@class CDVInAppBrowserViewController;
@interface CDVInAppBrowser : CDVPlugin {
- UIWindow * tmpWindow;
+ UIWindow * tmpWindow;
+
+ @private
+ BOOL _useBeforeload;
+ BOOL _waitForBeforeload;
}
@property (nonatomic, retain) CDVInAppBrowserViewController*
inAppBrowserViewController;
@@ -42,6 +46,7 @@
- (void)injectScriptCode:(CDVInvokedUrlCommand*)command;
- (void)show:(CDVInvokedUrlCommand*)command;
- (void)hide:(CDVInvokedUrlCommand*)command;
+- (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command;
@end
@@ -70,6 +75,7 @@
@property (nonatomic, assign) BOOL suppressesincrementalrendering;
@property (nonatomic, assign) BOOL hidden;
@property (nonatomic, assign) BOOL disallowoverscroll;
+@property (nonatomic, assign) BOOL beforeload;
+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options;
diff --git a/src/ios/CDVInAppBrowser.m b/src/ios/CDVInAppBrowser.m
index 0ca3feb15..afb5d215c 100644
--- a/src/ios/CDVInAppBrowser.m
+++ b/src/ios/CDVInAppBrowser.m
@@ -46,6 +46,8 @@ - (void)pluginInitialize
{
_previousStatusBarStyle = -1;
_callbackIdPattern = nil;
+ _useBeforeload = NO;
+ _waitForBeforeload = NO;
}
- (id)settingForKey:(NSString*)key
@@ -209,6 +211,10 @@ - (void)openInInAppBrowser:(NSURL*)url
withOptions:(NSString*)options
self.inAppBrowserViewController.webView.suppressesIncrementalRendering
= browserOptions.suppressesincrementalrendering;
}
+ // use of beforeload event
+ _useBeforeload = browserOptions.beforeload;
+ _waitForBeforeload = browserOptions.beforeload;
+
[self.inAppBrowserViewController navigateTo:url];
if (!browserOptions.hidden) {
[self show:nil];
@@ -304,6 +310,27 @@ - (void)openInSystem:(NSURL*)url
}
}
+- (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command
+{
+ NSString* urlStr = [command argumentAtIndex:0];
+
+ if (!_useBeforeload) {
+ NSLog(@"unexpected loadAfterBeforeload called without feature
beforeload=yes");
+ }
+ if (self.inAppBrowserViewController == nil) {
+ NSLog(@"Tried to invoke loadAfterBeforeload on IAB after it was
closed.");
+ return;
+ }
+ if (urlStr == nil) {
+ NSLog(@"loadAfterBeforeload called with nil argument, ignoring.");
+ return;
+ }
+
+ NSURL* url = [NSURL URLWithString:urlStr];
+ _waitForBeforeload = NO;
+ [self.inAppBrowserViewController navigateTo:url];
+}
+
// 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.
//
@@ -413,6 +440,7 @@ - (BOOL)webView:(UIWebView*)theWebView
shouldStartLoadWithRequest:(NSURLRequest*
{
NSURL* url = request.URL;
BOOL isTopLevelNavigation = [request.URL isEqual:[request
mainDocumentURL]];
+ BOOL shouldStart = YES;
// See if the url uses the 'gap-iab' protocol. If so, the host should be
the id of a callback to execute,
// and the path, if present, should be a JSON-encoded value to pass to the
callback.
@@ -440,11 +468,22 @@ - (BOOL)webView:(UIWebView*)theWebView
shouldStartLoadWithRequest:(NSURLRequest*
return NO;
}
}
+
+ // When beforeload=yes, on first URL change, initiate JS callback. Only
after the beforeload event, continue.
+ if (_waitForBeforeload && isTopLevelNavigation) {
+ CDVPluginResult* pluginResult = [CDVPluginResult
resultWithStatus:CDVCommandStatus_OK
+
messageAsDictionary:@{@"type":@"beforeload", @"url":[url absoluteString]}];
+ [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
+
+ [self.commandDelegate sendPluginResult:pluginResult
callbackId:self.callbackId];
+ return NO;
+ }
+
//if is an app store link, let the system handle it, otherwise it fails to
load it
- else if ([[ url scheme] isEqualToString:@"itms-appss"] || [[ url scheme]
isEqualToString:@"itms-apps"]) {
+ if ([[ url scheme] isEqualToString:@"itms-appss"] || [[ url scheme]
isEqualToString:@"itms-apps"]) {
[theWebView stopLoading];
[self openInSystem:url];
- return NO;
+ shouldStart = NO;
}
else if ((self.callbackId != nil) && isTopLevelNavigation) {
// Send a loadstart event for each top-level navigation (includes
redirects).
@@ -455,7 +494,11 @@ - (BOOL)webView:(UIWebView*)theWebView
shouldStartLoadWithRequest:(NSURLRequest*
[self.commandDelegate sendPluginResult:pluginResult
callbackId:self.callbackId];
}
- return YES;
+ if (_useBeforeload && isTopLevelNavigation) {
+ _waitForBeforeload = YES;
+ }
+
+ return shouldStart;
}
- (void)webViewDidStartLoad:(UIWebView*)theWebView
diff --git a/www/inappbrowser.js b/www/inappbrowser.js
index 3619f173f..7764765ad 100644
--- a/www/inappbrowser.js
+++ b/www/inappbrowser.js
@@ -33,6 +33,7 @@
function InAppBrowser () {
this.channels = {
+ 'beforeload': channel.create('beforeload'),
'loadstart': channel.create('loadstart'),
'loadstop': channel.create('loadstop'),
'loaderror': channel.create('loaderror'),
@@ -44,9 +45,17 @@
InAppBrowser.prototype = {
_eventHandler: function (event) {
if (event && (event.type in this.channels)) {
- this.channels[event.type].fire(event);
+ if (event.type === 'beforeload') {
+ this.channels[event.type].fire(event,
this._loadAfterBeforeload);
+ } else {
+ this.channels[event.type].fire(event);
+ }
}
},
+ _loadAfterBeforeload: function (strUrl) {
+ strUrl = urlutil.makeAbsolute(strUrl);
+ exec(null, null, 'InAppBrowser', 'loadAfterBeforeload', [strUrl]);
+ },
close: function (eventname) {
exec(null, null, 'InAppBrowser', 'close', []);
},
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
> Callback to decide whether to open link or not.
> -----------------------------------------------
>
> Key: CB-14188
> URL: https://issues.apache.org/jira/browse/CB-14188
> Project: Apache Cordova
> Issue Type: New Feature
> Components: cordova-plugin-inappbrowser
> Affects Versions: 3.0.0
> Reporter: wvengen
> Priority: Major
>
> Several times I've found myself wanting to tell inAppBrowser whether it can
> open a link in the embedded webview or using the system web browser. It would
> be great if there's a callback _before_ loading a page (loadstart is too late
> there), where I can tell inAppBrowser to load the page or not.
> CB-14013 introduced AllowedSchemes, but excluded the use of http and https.
> -It would be useful to allow intercepting http and https links, e.g. to
> decide whether to open the link in the system web browser or not.- At first I
> thought this mechanism could be used, but because of the asynchronous nature
> of Cordova callbacks, this didn't work out, and I added a beforeload
> callback. See comment for an example.
> I've submitted a PR -(my approach would be to generate a regexp based on
> AllowedSchemes and match the URL on that, instead of the current if logic)-.
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]