diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index c998deca5e30..e228a064f413 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -6,6 +6,7 @@ #include +#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) diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index cc2fd30c832f..e75cfb0267f0 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -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; diff --git a/atom/browser/api/lib/navigation-controller.coffee b/atom/browser/api/lib/navigation-controller.coffee index 75f9dd2097ca..f7945e07bf40 100644 --- a/atom/browser/api/lib/navigation-controller.coffee +++ b/atom/browser/api/lib/navigation-controller.coffee @@ -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 diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee index e249ccfb808d..eb86c94500ce 100644 --- a/atom/browser/api/lib/web-contents.coffee +++ b/atom/browser/api/lib/web-contents.coffee @@ -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 diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 1d00f6bdcf03..fbc09d9fe15f 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -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(); diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index cda0bd8e5cfb..cc69a1e12de8 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -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; diff --git a/atom/browser/lib/rpc-server.coffee b/atom/browser/lib/rpc-server.coffee index 1703f1e24751..48d00e9bd23b 100644 --- a/atom/browser/lib/rpc-server.coffee +++ b/atom/browser/lib/rpc-server.coffee @@ -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 diff --git a/atom/renderer/api/lib/remote.coffee b/atom/renderer/api/lib/remote.coffee index 673a01cb20b5..569678476587 100644 --- a/atom/renderer/api/lib/remote.coffee +++ b/atom/renderer/api/lib/remote.coffee @@ -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 diff --git a/atom/renderer/lib/override.coffee b/atom/renderer/lib/override.coffee index 6e02c2eb8222..1ca6e692ba21 100644 --- a/atom/renderer/lib/override.coffee +++ b/atom/renderer/lib/override.coffee @@ -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 diff --git a/docs/api/remote.md b/docs/api/remote.md index 77e76ea57f01..89bbc1f0606f 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -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