Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CB-14188: Add beforeload event, catching navigation before it happens #276

Merged
merged 1 commit into from
Oct 3, 2018

Conversation

wvengen
Copy link
Contributor

@wvengen wvengen commented Jul 16, 2018

Platforms affected

Android, iOS

What does this PR do?

Implements CB-14188: support for a callback that determines whether a URL to be loaded in the inAppBrowser should be loaded or not.

What testing has been done on this change?

On iOS & Android emulators (will test on real devices soon).

Checklist

  • Reported an issue in the JIRA database
  • Commit message follows the format: "CB-3232: (android) Fix bug with resolving file paths", where CB-xxxx is the JIRA ID & "android" is the platform affected.
  • Added automated test coverage as appropriate for this change: I'd be happy to add it once the feature is finished otherwise.
  • Added documentation for this change (added checklist item)
  • Research whether this is possible asynchronously
  • Use a synchronous callback

Example

app = cordova.InAppBrowser.open(url, "_blank", "beforeload=yes")
app.addEventListener("beforeload", function(e, cb) {
  if (e.url.startsWith("https://example.com/")) {
    cb(e.url); // Tell inAppBrowser to open the URL indeed.
  } else {
    alert("Opened external URL: " + e.url);
  }
}, false);

@wvengen wvengen force-pushed the feature/beforeload-event branch 2 times, most recently from a49c353 to bbbe2cb Compare July 16, 2018 11:45
@brodycj
Copy link

brodycj commented Jul 17, 2018

Looks nice in general. A couple major comments on my part:

The idea of passing an asynchronous callback to an event listener seems really strange to me. While I can definitely understand the logic behind making it asynchronous between native and JavaScript I don't think this really justifies introducing what looks like new paradigm in event listeners. I can think of the following alternative approaches:

  • event listener synchronously returns non-null value to indicate that application does not want to load the URL, in a similar fashion to a standard beforeload event handler ref: [1] (preferred)
  • event listener throws an exception to override default behavior, in a similar fashion to backbutton event on Windows ref: [2]
  • new asynchronous callback mechanism outside the event handler mechanism that the application can use to filter URL load requests

The code also seems to assume that there would never be multiple outstanding load requests, which I would not agree with. What if a user clicks on a couple links in succession, or the webpage JavaScript issues multiple HTTP(S) requests?

[1] https://eloquentjavascript.net/15_event.html#p_nu8/BUQa7r
[2] https://cordova.apache.org/docs/en/latest/cordova/events/events.html#windows-quirks

@wvengen
Copy link
Contributor Author

wvengen commented Jul 18, 2018

Thanks a lot for your review and comments, @brodybits. I agree that the current approach is not ideal, and have struggled with how to add the callback. Indeed, a synchronous callback would be the best option, that would first need some research to whether Android's and iOS's WebView implementation allow this to take a little time (because it involves a Javascript invocation).

If this is not possible (or if this is ported to a platform requiring near-immediate return from its do-I-need-to-load-this-URL-function), for Cordova users it can still be a synchronous function, with the help of a workaround similar to what happens now, but without the concurrency issue you mentioned (I have an idea to do this using a custom URL scheme).

Interesting you mention the beforeunload event, that would be familiar to many. For inAppBrowser, the confirm dialog would not be shown. It also makes sense to skip the callback on first page load, as that is controlled by the inAppBrowser-invoking code already.

I'll delve into this. Since I'll be on holiday for about two weeks, it may take a little time.

@wvengen
Copy link
Contributor Author

wvengen commented Aug 1, 2018

Reading up on HTML's beforeunload event, I do see preventDefault(), e.g. on MDN, W3C HTML 5.0 (suggesting e.returnValue) and WHATWG (preferring e.preventDefault()).

I would suggest to adopt e.returnValue and e.preventDefault() in InAppBrowser's new beforeunload event. This is in-line with current standards, allows using the existing event handling infrastructure, and by updating the event this will also work with multiple event handlers. It does require some changes to the event object passed on to the handlers (so that returnValue can be reported back, and e.preventDefault() is available).

@wvengen
Copy link
Contributor Author

wvengen commented Aug 1, 2018

I'd also suggest to explicitely enable the event (with an option like beforeunload=yes when opening the InAppBrowser), so that we're sure there is no performance penalty (if any). We can always consider removing the option in the future, if it doesn't turn out to be an issue in practice.

@janpio
Copy link
Member

janpio commented Oct 1, 2018

Hey, I just fixed the problem that caused Android tests to fail in master. Could you rebase this PR please? This should get rid of the Android failures and possibly fix all test failures for this PR.

@wvengen
Copy link
Contributor Author

wvengen commented Oct 2, 2018

@janpio still failing on Android 7 :(

@wvengen wvengen changed the title CB-14188: add beforeload event, catching navigation before it happens CB-14188: WIP Add beforeload event, catching navigation before it happens Oct 2, 2018
@janpio
Copy link
Member

janpio commented Oct 2, 2018

Yep, you are unfortunately hitting this: #307

@janpio janpio changed the title CB-14188: WIP Add beforeload event, catching navigation before it happens CB-14188: Add beforeload event, catching navigation before it happens Oct 2, 2018
@janpio
Copy link
Member

janpio commented Oct 2, 2018

And passing :) (context: #307 (comment))

@brodycj
Copy link

brodycj commented Oct 3, 2018

Looks OK to me, merging

@brodycj brodycj merged commit eafaeda into apache:master Oct 3, 2018
@janpio
Copy link
Member

janpio commented Oct 3, 2018

This is already merged now, but can this be added to the tests and checked automatically that it works?

@wvengen
Copy link
Contributor Author

wvengen commented Oct 5, 2018

Oh, wait, wasn't expecting this to be merged already ... I was still coming back to processing the feedback of @brodybits on the callback mechanism. I suppose these points are still valid ... ?

I'm also ok with having this PR included right now (so the feature can be used), and changing the API later (in a next major release), if somebody has a better way of implementing it. Or mark the API as unstable, so it can be changed in a point release. What shall we do?

this.webView = webView;
this.edittext = mEditText;
this.useBeforeload = useBeforeload;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 2 vars that will always store the same value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(this is merged already, but perhaps my reply will serve as a reference)
waitForBeforeload is the current state, whether we need to wait a call back from JS to really load next time it is encountered. useBeforeload indicates whether the beforeload event is used at all (see the end of shouldOverrideUrlLoading).

@janpio
Copy link
Member

janpio commented Oct 30, 2018

Yes, I agree that the feedback is valid - I have no idea why @brodybits just merged it after giving this feedback himself. Could you please create a new PR and refer to this one so it all gets connected? Thanks.

@brodycj
Copy link

brodycj commented Oct 30, 2018

I was hoping to unblock forward progress, looks like it wasn't so good. I cannot promise when I will get a chance to follow up again. Sorry for the troubles.

@wvengen I do stand by the feedback I gave before, would like to treat them as minor points in case anyone has a chance to do it better someday.

@purplecabbage
Copy link
Contributor

Not a blocker, just a little nit.
Keep moving forwards.

@wvengen
Copy link
Contributor Author

wvengen commented Oct 31, 2018

Ah, that clears it up. And thanks for merging: with these minor points I think it indeed makes sense to include it already, and if interest in this feature would increase, it can be improved.
I'll open an issue to track this.

Thanks again for your support, @brodybits!

janpio pushed a commit that referenced this pull request Nov 21, 2018
For both UIWebView and WKWebView implementations on iOS.

<!--
Please make sure the checklist boxes are all checked before submitting the PR. The checklist
is intended as a quick reference, for complete details please see our Contributor Guidelines:

http://cordova.apache.org/contribute/contribute_guidelines.html

Thanks!
-->

### Platforms affected
iOS

### What does this PR do?
Fixes `beforeload` event (introduced by #276) for iOS

### What testing has been done on this change?
Tested both allow & deny loading of URL with both iOS implementations in [test container app](https://github.com/dpa99c/cordova-plugin-inappbrowser-wkwebview-test) (ignore its README).

- To test with UIWebView use options: `beforeload=yes,usewkwebview=no`
- To test with WKWebView use options: `beforeload=yes,usewkwebview=yes`

### Checklist
- [x] [Reported an issue](http://cordova.apache.org/contribute/issues.html) in the JIRA database
- [x] Commit message follows the format: "CB-3232: (android) Fix bug with resolving file paths", where CB-xxxx is the JIRA ID & "android" is the platform affected.
- [x] Added automated test coverage as appropriate for this change.

closes #349
@jezmck
Copy link
Contributor

jezmck commented Apr 11, 2019

Sorry for the simple question, is this in the current release (v3.0.0)?
I've not been able to catch this event.

wvengen added a commit to q-m/cordova-web-wrap that referenced this pull request Jun 13, 2019
This gets rid of the previous workarounds by using the beforeload event
introduced in apache/cordova-plugin-inappbrowser#276
wvengen added a commit to q-m/cordova-web-wrap that referenced this pull request Jun 13, 2019
This gets rid of the previous workarounds by using the beforeload event
introduced in apache/cordova-plugin-inappbrowser#276
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants