Skip to content

Commit

Permalink
feat: add will-frame-navigate event (#34418)
Browse files Browse the repository at this point in the history
  • Loading branch information
Milan Burda committed Apr 11, 2023
1 parent 6f9cc3c commit b118cbe
Show file tree
Hide file tree
Showing 13 changed files with 550 additions and 29 deletions.
3 changes: 0 additions & 3 deletions docs/api/structures/event.md

This file was deleted.

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`.

### Document Navigations

When a `webContents` navigates to another page (as opposed to an [in-page navigation](web-contents.md#in-page-navigation)), 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.

### 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)

### 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 @@ -210,9 +240,37 @@ Returns:
* `event` Event
* `url` string

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

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
1 change: 0 additions & 1 deletion filenames.auto.gni
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ auto_filenames = {
"docs/api/structures/custom-scheme.md",
"docs/api/structures/desktop-capturer-source.md",
"docs/api/structures/display.md",
"docs/api/structures/event.md",
"docs/api/structures/extension-info.md",
"docs/api/structures/extension.md",
"docs/api/structures/file-filter.md",
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 @@ -158,6 +158,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
});
});

// 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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
"@azure/storage-blob": "^12.9.0",
"@dsanders11/vscode-markdown-languageservice": "^0.3.0-alpha.4",
"@electron/asar": "^3.2.1",
"@electron/docs-parser": "^1.0.0",
"@electron/docs-parser": "^1.1.0",
"@electron/fiddle-core": "^1.0.4",
"@electron/github-app-auth": "^1.5.0",
"@electron/typescript-definitions": "^8.10.0",
"@electron/typescript-definitions": "^8.14.0",
"@octokit/rest": "^19.0.7",
"@primer/octicons": "^10.0.0",
"@types/basic-auth": "^1.1.3",
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 @@ -622,6 +622,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 @@ -1761,18 +1778,8 @@ bool WebContents::EmitNavigationEvent(
const std::string& event,
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)) {
return CANCEL;
}
if (handle->IsRendererInitiated() && handle->IsInMainFrame() &&
api_contents->EmitNavigationEvent("will-navigate", handle)) {
return CANCEL;
Expand Down

0 comments on commit b118cbe

Please sign in to comment.