Merge pull request #1646 from atom/navigation-in-page
Fix handling in-page navigations
This commit is contained in:
commit
4ca8039104
10 changed files with 103 additions and 15 deletions
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <set>
|
||||
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_javascript_dialog_manager.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
|
@ -348,8 +349,9 @@ void WebContents::WebContentsDestroyed() {
|
|||
}
|
||||
|
||||
void WebContents::NavigationEntryCommitted(
|
||||
const content::LoadCommittedDetails& load_details) {
|
||||
Emit("navigation-entry-commited", load_details.entry->GetURL());
|
||||
const content::LoadCommittedDetails& details) {
|
||||
Emit("navigation-entry-commited", details.entry->GetURL(),
|
||||
details.is_in_page, details.did_replace_entry);
|
||||
}
|
||||
|
||||
void WebContents::DidAttach(int guest_proxy_routing_id) {
|
||||
|
@ -442,6 +444,21 @@ void WebContents::ReloadIgnoringCache() {
|
|||
web_contents()->GetController().ReloadIgnoringCache(false);
|
||||
}
|
||||
|
||||
void WebContents::GoBack() {
|
||||
atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
|
||||
web_contents()->GetController().GoBack();
|
||||
}
|
||||
|
||||
void WebContents::GoForward() {
|
||||
atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
|
||||
web_contents()->GetController().GoForward();
|
||||
}
|
||||
|
||||
void WebContents::GoToOffset(int offset) {
|
||||
atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce();
|
||||
web_contents()->GetController().GoToOffset(offset);
|
||||
}
|
||||
|
||||
int WebContents::GetRoutingID() const {
|
||||
return web_contents()->GetRoutingID();
|
||||
}
|
||||
|
@ -610,6 +627,9 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
|||
.SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
|
||||
.SetMethod("_stop", &WebContents::Stop)
|
||||
.SetMethod("_reloadIgnoringCache", &WebContents::ReloadIgnoringCache)
|
||||
.SetMethod("_goBack", &WebContents::GoBack)
|
||||
.SetMethod("_goForward", &WebContents::GoForward)
|
||||
.SetMethod("_goToOffset", &WebContents::GoToOffset)
|
||||
.SetMethod("getRoutingId", &WebContents::GetRoutingID)
|
||||
.SetMethod("getProcessId", &WebContents::GetProcessID)
|
||||
.SetMethod("isCrashed", &WebContents::IsCrashed)
|
||||
|
|
|
@ -53,6 +53,9 @@ class WebContents : public mate::EventEmitter,
|
|||
bool IsWaitingForResponse() const;
|
||||
void Stop();
|
||||
void ReloadIgnoringCache();
|
||||
void GoBack();
|
||||
void GoForward();
|
||||
void GoToOffset(int offset);
|
||||
int GetRoutingID() const;
|
||||
int GetProcessID() const;
|
||||
bool IsCrashed() const;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
ipc = require 'ipc'
|
||||
|
||||
# The history operation in renderer is redirected to browser.
|
||||
ipc.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) ->
|
||||
event.sender[method] args...
|
||||
|
||||
# JavaScript implementation of Chromium's NavigationController.
|
||||
# Instead of relying on Chromium for history control, we compeletely do history
|
||||
# control on user land, and only rely on WebContents.loadUrl for navigation.
|
||||
|
@ -8,17 +14,28 @@ class NavigationController
|
|||
@history = []
|
||||
@currentIndex = -1
|
||||
@pendingIndex = -1
|
||||
@inPageIndex = -1
|
||||
|
||||
@webContents.on 'navigation-entry-commited', (event, url) =>
|
||||
if @pendingIndex is -1 # Normal navigation.
|
||||
@history = @history.slice 0, @currentIndex + 1 # Clear history.
|
||||
if @history[@currentIndex] isnt url
|
||||
@currentIndex++
|
||||
@history.push url
|
||||
else # Go to index.
|
||||
@webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) =>
|
||||
if @inPageIndex > -1 and not inPage
|
||||
# Navigated to a new page, clear in-page mark.
|
||||
@inPageIndex = -1
|
||||
else if @inPageIndex is -1 and inPage
|
||||
# Started in-page navigations.
|
||||
@inPageIndex = @currentIndex
|
||||
|
||||
if @pendingIndex >= 0 # Go to index.
|
||||
@currentIndex = @pendingIndex
|
||||
@pendingIndex = -1
|
||||
@history[@currentIndex] = url
|
||||
else if replaceEntry # Non-user initialized navigation.
|
||||
@history[@currentIndex] = url
|
||||
else # Normal navigation.
|
||||
@history = @history.slice 0, @currentIndex + 1 # Clear history.
|
||||
currentEntry = @history[@currentIndex]
|
||||
if currentEntry?.url isnt url
|
||||
@currentIndex++
|
||||
@history.push url
|
||||
|
||||
loadUrl: (url, options={}) ->
|
||||
@pendingIndex = -1
|
||||
|
@ -57,21 +74,32 @@ class NavigationController
|
|||
goBack: ->
|
||||
return unless @canGoBack()
|
||||
@pendingIndex = @getActiveIndex() - 1
|
||||
@webContents._loadUrl @history[@pendingIndex], {}
|
||||
if @inPageIndex > -1 and @pendingIndex >= @inPageIndex
|
||||
@webContents._goBack()
|
||||
else
|
||||
@webContents._loadUrl @history[@pendingIndex], {}
|
||||
|
||||
goForward: ->
|
||||
return unless @canGoForward()
|
||||
@pendingIndex = @getActiveIndex() + 1
|
||||
@webContents._loadUrl @history[@pendingIndex], {}
|
||||
if @inPageIndex > -1 and @pendingIndex >= @inPageIndex
|
||||
@webContents._goForward()
|
||||
else
|
||||
@webContents._loadUrl @history[@pendingIndex], {}
|
||||
|
||||
goToIndex: (index) ->
|
||||
return unless @canGoToIndex index
|
||||
@pendingIndex = index
|
||||
@webContents._loadUrl @history[@pendingIndex], {}
|
||||
@webContents._loadUrl @history[@pendingIndex].url, {}
|
||||
|
||||
goToOffset: (offset) ->
|
||||
return unless @canGoToOffset offset
|
||||
@goToIndex @currentIndex + offset
|
||||
pendingIndex = @currentIndex + offset
|
||||
if @inPageIndex > -1 and pendingIndex >= @inPageIndex
|
||||
@pendingIndex = pendingIndex
|
||||
@webContents._goToOffset offset
|
||||
else
|
||||
@goToIndex pendingIndex
|
||||
|
||||
getActiveIndex: ->
|
||||
if @pendingIndex is -1 then @currentIndex else @pendingIndex
|
||||
|
|
|
@ -29,7 +29,6 @@ module.exports.wrap = (webContents) ->
|
|||
|
||||
# The navigation controller.
|
||||
controller = new NavigationController(webContents)
|
||||
webContents.controller = controller
|
||||
for name, method of NavigationController.prototype when method instanceof Function
|
||||
do (name, method) ->
|
||||
webContents[name] = -> method.apply controller, arguments
|
||||
|
|
|
@ -32,6 +32,9 @@ namespace atom {
|
|||
|
||||
namespace {
|
||||
|
||||
// Next navigation should not restart renderer process.
|
||||
bool g_suppress_renderer_process_restart = false;
|
||||
|
||||
struct FindByProcessId {
|
||||
explicit FindByProcessId(int child_process_id)
|
||||
: child_process_id_(child_process_id) {
|
||||
|
@ -51,6 +54,11 @@ struct FindByProcessId {
|
|||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void AtomBrowserClient::SuppressRendererProcessRestartForOnce() {
|
||||
g_suppress_renderer_process_restart = true;
|
||||
}
|
||||
|
||||
AtomBrowserClient::AtomBrowserClient()
|
||||
: dying_render_process_(nullptr) {
|
||||
}
|
||||
|
@ -131,6 +139,11 @@ void AtomBrowserClient::OverrideSiteInstanceForNavigation(
|
|||
content::SiteInstance* current_instance,
|
||||
const GURL& url,
|
||||
content::SiteInstance** new_instance) {
|
||||
if (g_suppress_renderer_process_restart) {
|
||||
g_suppress_renderer_process_restart = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_instance->HasProcess())
|
||||
dying_render_process_ = current_instance->GetProcess();
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
|||
AtomBrowserClient();
|
||||
virtual ~AtomBrowserClient();
|
||||
|
||||
// Don't force renderer process to restart for once.
|
||||
static void SuppressRendererProcessRestartForOnce();
|
||||
|
||||
protected:
|
||||
// content::ContentBrowserClient:
|
||||
void RenderProcessWillLaunch(content::RenderProcessHost* host) override;
|
||||
|
|
|
@ -107,6 +107,9 @@ ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, guestInstanceId) ->
|
|||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CURRENT_WEB_CONTENTS', (event) ->
|
||||
event.returnValue = valueToMeta event.sender, event.sender
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) ->
|
||||
try
|
||||
args = unwrapArgs event.sender, args
|
||||
|
|
|
@ -110,13 +110,20 @@ exports.require = (module) ->
|
|||
meta = ipc.sendSync 'ATOM_BROWSER_REQUIRE', module
|
||||
moduleCache[module] = metaToValue meta
|
||||
|
||||
# Get current window object.
|
||||
# Get current BrowserWindow object.
|
||||
windowCache = null
|
||||
exports.getCurrentWindow = ->
|
||||
return windowCache if windowCache?
|
||||
meta = ipc.sendSync 'ATOM_BROWSER_CURRENT_WINDOW', process.guestInstanceId
|
||||
windowCache = metaToValue meta
|
||||
|
||||
# Get current WebContents object.
|
||||
webContentsCache = null
|
||||
exports.getCurrentWebContents = ->
|
||||
return webContentsCache if webContentsCache?
|
||||
meta = ipc.sendSync 'ATOM_BROWSER_CURRENT_WEB_CONTENTS'
|
||||
webContentsCache = metaToValue meta
|
||||
|
||||
# Get a global object in browser.
|
||||
exports.getGlobal = (name) ->
|
||||
meta = ipc.sendSync 'ATOM_BROWSER_GLOBAL', name
|
||||
|
|
|
@ -74,9 +74,17 @@ window.confirm = (message, title='') ->
|
|||
window.prompt = ->
|
||||
throw new Error('prompt() is and will not be supported.')
|
||||
|
||||
# Simple implementation of postMessage.
|
||||
window.opener =
|
||||
postMessage: (message, targetOrigin='*') ->
|
||||
ipc.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', message, targetOrigin
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (message, targetOrigin) ->
|
||||
window.postMessage message, targetOrigin
|
||||
|
||||
# Forward history operations to browser.
|
||||
sendHistoryOperation = (args...) ->
|
||||
ipc.send 'ATOM_SHELL_NAVIGATION_CONTROLLER', args...
|
||||
window.history.back = -> sendHistoryOperation 'goBack'
|
||||
window.history.forward = -> sendHistoryOperation 'goForward'
|
||||
window.history.go = (offset) -> sendHistoryOperation 'goToOffset', offset
|
||||
|
|
|
@ -138,6 +138,10 @@ Returns the object returned by `require(module)` in the main process.
|
|||
Returns the [BrowserWindow](browser-window.md) object which this web page
|
||||
belongs to.
|
||||
|
||||
## remote.getCurrentWebContent()
|
||||
|
||||
Returns the WebContents object of this web page.
|
||||
|
||||
## remote.getGlobal(name)
|
||||
|
||||
* `name` String
|
||||
|
|
Loading…
Reference in a new issue