[ 
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]

Reply via email to