Merge pull request #1646 from atom/navigation-in-page

Fix handling in-page navigations
This commit is contained in:
Cheng Zhao 2015-05-11 19:47:15 +08:00
commit 4ca8039104
10 changed files with 103 additions and 15 deletions

View file

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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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