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

feat: add will-frame-navigate event #34418

Merged
merged 27 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2b9d6ec
feat: add will-navigate-in-frame event to webContents
itsananderson Oct 6, 2021
c56ebdb
docs: add documentation for webview will-frame-navigate event
itsananderson May 20, 2022
0dbc394
feat: Eliminate isInPlace argument from will-frame-navigate event
itsananderson Jun 2, 2022
5227c91
fix: Fire will-frame-navigate before will-navigate
itsananderson Jun 2, 2022
42faabd
feat: send will-frame-navigate with a WebFrameMain in the event details
itsananderson Jun 14, 2022
64f3379
docs: Update WebContents docs for new API signature
itsananderson Jun 14, 2022
28c9eed
feat: Add custom event forwarding for <webview> will-frame-navigate
itsananderson Jun 14, 2022
29edf5e
fix: wrap WebFrameMain so it can be sent as an event
itsananderson Jun 14, 2022
6bf2820
test: update webContents and <webview> tests to match new signatures
itsananderson Jun 14, 2022
361eb29
chore: undo unnecessary change
itsananderson Jun 14, 2022
164ac12
fix: don't switch will-navigate to use EmitNavigationEventDetails
itsananderson Jun 14, 2022
d64d558
test: clean up will-navigate and will-frame-navigate tests for <webview>
itsananderson Jun 14, 2022
aadd9aa
chore: apply lint fixes
itsananderson Jun 14, 2022
c14985a
chore: move GetRenderFrameHost helper into anonymous namespace
itsananderson Jun 24, 2022
af46d89
docs: auto-generate WillFrameNavigateDetails rather than defining it …
itsananderson Jun 24, 2022
76baaf2
test: Update <webview> tests to actually pass under new spec runner
itsananderson Sep 2, 2022
717e578
docs: Add section explaining relationship between various nav events
itsananderson Sep 20, 2022
4d83aba
Merge remote-tracking branch 'upstream/main' into add-will-frame-navi…
itsananderson Feb 5, 2023
d86c324
test: Add some tests to ensure navigation event order doesn't silentl…
itsananderson Feb 5, 2023
577dfad
test: Always monitor all nav events to ensure unexpected ones don't fire
itsananderson Feb 6, 2023
8c64f3a
test: Add test to verify in-page navigation event order
itsananderson Feb 6, 2023
f534b94
Merge branch 'main' into add-will-frame-navigate
itsananderson Feb 6, 2023
a8087d4
Merge branch 'main' into add-will-frame-navigate
miniak Mar 9, 2023
14937f8
feat: Change to new style where extra params are exposed as event props
itsananderson Mar 3, 2023
aa126b0
fix: Remove unused EmitNavigationEventDetails
itsananderson Mar 3, 2023
addd531
fix: Update tests to use new async helpers
itsananderson Mar 9, 2023
37af256
docs: Rename and reorder sections documenting navigation events
itsananderson Mar 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 59 additions & 1 deletion docs/api/web-contents.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,36 @@ const contents = win.webContents
console.log(contents)
```

## Navigation Events

Several events can be used to monitor navigations as they occur within a `webContents`.

### In-page Navigation

In-page navigations don't cause the page to reload, but instead navigate to a location within the current page. These events are not cancellable. For an in-page navigations, the following events will fire in this order:

* [`did-start-navigation`](web-contents.md#event-did-start-navigation)
* [`did-navigate-in-page`](web-contents.md#event-did-navigate-in-page)
itsananderson marked this conversation as resolved.
Show resolved Hide resolved

### Non-in-page Navigations
itsananderson marked this conversation as resolved.
Show resolved Hide resolved

When a `webContents` navigates to another page, the following events will be fired.

* [`did-start-navigation`](web-contents.md#event-did-start-navigation)
* [`will-frame-navigate`](web-contents.md#event-will-frame-navigate)
* [`will-navigate`](web-contents.md#event-will-navigate) (only fired when main frame navigates)
* [`will-redirect`](web-contents.md#event-will-redirect) (only fired when a redirect happens during navigation)
* [`did-redirect-navigation`](web-contents.md#event-did-redirect-navigation) (only fired when a redirect happens during navigation)
* [`did-frame-navigate`](web-contents.md#event-did-frame-navigate)
* [`did-navigate`](web-contents.md#event-did-navigate) (only fired when main frame navigates)

Subsequent events will not fire if `event.preventDefault()` is called on any of the cancellable events.

### Frame Navigation

The [`will-navigate`](web-contents.md#event-will-navigate) and [`did-navigate`](web-contents.md#event-did-navigate) events only fire when the [mainFrame](web-contents.md#contentsmainframe-readonly) navigates.
If you want to also observe navigations in `<iframe>`s, use [`will-frame-navigate`](web-contents.md#event-will-frame-navigate) and [`did-frame-navigate`](web-contents.md#event-did-frame-navigate) events.

## Methods

These methods can be accessed from the `webContents` module:
Expand Down Expand Up @@ -225,9 +255,37 @@ Returns:
* `frameProcessId` Integer _Deprecated_
* `frameRoutingId` Integer _Deprecated_

Emitted when a user or the page wants to start navigation. It can happen when
Emitted when a user or the page wants to start navigation on the main frame. It can happen when
the `window.location` object is changed or a user clicks a link in the page.

This event will not emit when the navigation is started programmatically with
APIs like `webContents.loadURL` and `webContents.back`.

It is also not emitted for in-page navigations, such as clicking anchor links
or updating the `window.location.hash`. Use `did-navigate-in-page` event for
this purpose.

Calling `event.preventDefault()` will prevent the navigation.

#### Event: 'will-frame-navigate'

Returns:

* `details` Event<>
* `url` string - The URL the frame is navigating to.
* `isMainFrame` boolean - True if the navigation is taking place in a main frame.
* `frame` WebFrameMain - The frame to be navigated.
* `initiator` WebFrameMain (optional) - The frame which initiated the
navigation, which can be a parent frame (e.g. via `window.open` with a
frame's name), or null if the navigation was not initiated by a frame. This
can also be null if the initiating frame was deleted before the event was
emitted.

Emitted when a user or the page wants to start navigation in any frame. It can happen when
the `window.location` object is changed or a user clicks a link in the page.

Unlike `will-navigate`, `will-frame-navigate` is fired when the main frame or any of its subframes attempts to navigate. When the navigation event comes from the main frame, `isMainFrame` will be `true`.

This event will not emit when the navigation is started programmatically with
APIs like `webContents.loadURL` and `webContents.back`.

Expand Down
22 changes: 22 additions & 0 deletions docs/api/webview-tag.md
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,28 @@ this purpose.

Calling `event.preventDefault()` does __NOT__ have any effect.

### Event: 'will-frame-navigate'

Returns:

* `url` string
* `isMainFrame` boolean
* `frameProcessId` Integer
* `frameRoutingId` Integer
ckerr marked this conversation as resolved.
Show resolved Hide resolved

Emitted when a user or the page wants to start navigation anywhere in the `<webview>`
or any frames embedded within. It can happen when the `window.location` object is
changed or a user clicks a link in the page.

This event will not emit when the navigation is started programmatically with
APIs like `<webview>.loadURL` and `<webview>.back`.

It is also not emitted during in-page navigation, such as clicking anchor links
or updating the `window.location.hash`. Use `did-navigate-in-page` event for
this purpose.

Calling `event.preventDefault()` does __NOT__ have any effect.

### Event: 'did-start-navigation'

Returns:
Expand Down
10 changes: 10 additions & 0 deletions lib/browser/guest-view-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,16 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
});
});

// Dispatch guest's frame navigation event to embedder.
guest.on('will-frame-navigate', function (event: Electron.WebContentsWillFrameNavigateEventParams) {
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'will-frame-navigate', {
url: event.url,
isMainFrame: event.isMainFrame,
frameProcessId: event.frame.processId,
frameRoutingId: event.frame.routingId
});
});
itsananderson marked this conversation as resolved.
Show resolved Hide resolved

// Notify guest of embedder window visibility when it is ready
// FIXME Remove once https://github.com/electron/electron/issues/6828 is fixed
guest.on('dom-ready', function () {
Expand Down
29 changes: 18 additions & 11 deletions shell/browser/api/electron_api_web_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,23 @@ void SetBackgroundColor(content::RenderWidgetHostView* rwhv, SkColor color) {
->SetContentBackgroundColor(color);
}

content::RenderFrameHost* GetRenderFrameHost(
content::NavigationHandle* navigation_handle) {
int frame_tree_node_id = navigation_handle->GetFrameTreeNodeId();
content::FrameTreeNode* frame_tree_node =
content::FrameTreeNode::GloballyFindByID(frame_tree_node_id);
content::RenderFrameHostManager* render_manager =
frame_tree_node->render_manager();
content::RenderFrameHost* frame_host = nullptr;
if (render_manager) {
frame_host = render_manager->speculative_frame_host();
if (!frame_host)
frame_host = render_manager->current_frame_host();
}

return frame_host;
}

} // namespace

#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
Expand Down Expand Up @@ -1769,18 +1786,8 @@ bool WebContents::EmitNavigationEvent(
const std::string& event_name,
content::NavigationHandle* navigation_handle) {
bool is_main_frame = navigation_handle->IsInMainFrame();
int frame_tree_node_id = navigation_handle->GetFrameTreeNodeId();
content::FrameTreeNode* frame_tree_node =
content::FrameTreeNode::GloballyFindByID(frame_tree_node_id);
content::RenderFrameHostManager* render_manager =
frame_tree_node->render_manager();
content::RenderFrameHost* frame_host = nullptr;
if (render_manager) {
frame_host = render_manager->speculative_frame_host();
if (!frame_host)
frame_host = render_manager->current_frame_host();
}
int frame_process_id = -1, frame_routing_id = -1;
content::RenderFrameHost* frame_host = GetRenderFrameHost(navigation_handle);
if (frame_host) {
frame_process_id = frame_host->GetProcess()->GetID();
frame_routing_id = frame_host->GetRoutingID();
Expand Down
4 changes: 4 additions & 0 deletions shell/browser/electron_navigation_throttle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ ElectronNavigationThrottle::WillStartRequest() {
return PROCEED;
}

if (handle->IsRendererInitiated() &&
api_contents->EmitNavigationEvent("will-frame-navigate", handle)) {
zcbenz marked this conversation as resolved.
Show resolved Hide resolved
return CANCEL;
}
if (handle->IsRendererInitiated() && handle->IsInMainFrame() &&
api_contents->EmitNavigationEvent("will-navigate", handle)) {
return CANCEL;
Expand Down