From 3f546e6babbc9becc844cfb626045def83a358be Mon Sep 17 00:00:00 2001 From: Fritz Lin Date: Thu, 3 Sep 2015 22:27:22 +0800 Subject: [PATCH 1/8] Add docs-translations for zh-CN - development/coding-style - development/atom-shell-vs-node-webkit --- .../development/atom-shell-vs-node-webkit.md | 29 ++++++++++++++++++ .../zh-CN/development/coding-style.md | 30 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md create mode 100644 docs-translations/zh-CN/development/coding-style.md diff --git a/docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md b/docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md new file mode 100644 index 0000000000..cf6859d506 --- /dev/null +++ b/docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md @@ -0,0 +1,29 @@ +# Electron 和 NW.js (原名 node-webkit) 在技术上的差异 + +__备注:Electron 的原名是 Atom Shell。__ + +与 NW.js 相似,Electron 提供了一个能通过 JavaScript 和 HTML 创建桌面应用的平台,同时集成 Node 来授予网页访问底层系统的权限。 + +但是这两个项目也有本质上的区别,使得 Electron 和 NW.js 成为两个相互独立的产品。 + +__1. 应用的入口__ + +在 NW.js 中,一个应用的主入口是一个页面。你在 `package.json` 中指定一个主页面,它会作为应用的主窗口被打开。 + +在 Electron 中,入口是一个 JavaScript 脚本。不同于直接提供一个URL,你需要手动创建一个浏览器窗口,然后通过 API 加载 HTML 文件。你还可以监听窗口事件,决定何时让应用退出。 + +Electron 的工作方式更像 Node.js 运行时。 Electron 的 APIs 更加底层,因此你可以它替代 [PhantomJS](http://phantomjs.org/) 做浏览器测试。 + +__2. 构建系统__ + +为了避免构建整个 Chromium 带来的复杂度,Electron 通过 [`libchromiumcontent`](https://github.com/brightray/libchromiumcontent) 来访问 Chromium 的 Content API。`libchromiumcontent` 是一个独立的、引入了 Chromium Content 模块及其所有依赖的共享库。用户不需要一个强劲的机器来构建 Electron。 + +__3. Node 集成__ + +在 NW.js,网页中的 Node 集成需要通过给 Chromium 打补丁来实现。但在 Electron 中,我们选择了另一种方式:通过各个平台的消息循环与 libuv 的循环集成,避免了直接在 Chromium 上做改动。你可以看 [`node_bindings`](../../atom/common/) 来了解这是如何完成的。 + +__4. 多上下文__ + +如果你是有经验的 NW.js 用户,你应该会熟悉 Node 上下文和 web 上下文的概念。这些概念的产生源于 NW.js 的实现方式。 + +通过使用 Node 的[多上下文](http://strongloop.com/strongblog/whats-new-node-js-v0-12-multiple-context-execution/)特性,Electron不需要在网页中引入新的 JavaScript 上下文。 diff --git a/docs-translations/zh-CN/development/coding-style.md b/docs-translations/zh-CN/development/coding-style.md new file mode 100644 index 0000000000..82219467b1 --- /dev/null +++ b/docs-translations/zh-CN/development/coding-style.md @@ -0,0 +1,30 @@ +# 编码规范 + +以下是 Electron 项目中代码书写规范的指导方针。 + +## C++ 和 Python + +对于 C++ 和 Python,我们追随 Chromium 的[Coding +Style](http://www.chromium.org/developers/coding-style)。你可以通过 `script/cpplint.py` 来检验所有文件是否符合要求。 + +我们使用的 Pyhton 版本是 Python 2.7。 + +其中 C++ 代码中用到了许多 Chromium 的抽象和类型,我们希望你对其有所熟悉。一个好的去处是 +Chromium 的[重要的抽象和数据结构](https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures)。这个文档提到了一些特殊的类型、域内类型(当超出作用域时会自动释放内存)、日志机制等等。 + +## CoffeeScript + +对于 CoffeeScript,我们追随 GitHub 的[Style +Guide](https://github.com/styleguide/javascript) 及如下规则: + +* 文件不应该以换行结尾,因为我们要匹配 Google 的规范。 +* 文件名应该以 `-` 作连接而不是 `_`,等等。 + `file-name.coffee` 而不是 `file_name.coffee`,因为在 + [github/atom](https://github.com/github/atom) 模块名通常都是 `module-name` 的形式。这条规则仅应用于 `.coffee` 文件。 + +## API 名称 + +当新建一个API时,我们应该倾向于 getters 和 setters 的方式,而不是 +jQuery 的单函数形式。例如,`.getText()` 和 `.setText(text)` + 优于 `.text([text])`。这里是相关的 +[讨论记录](https://github.com/atom/electron/issues/46)。 From d180d3b1682e2d633ceb4e09bb675a1c463d8da5 Mon Sep 17 00:00:00 2001 From: Robo Date: Thu, 6 Aug 2015 20:31:05 +0530 Subject: [PATCH 2/8] webview: fix partition attribute --- atom/browser/api/atom_api_web_contents.cc | 10 ++++-- atom/browser/api/atom_api_web_view_manager.cc | 3 +- atom/browser/atom_browser_main_parts.cc | 32 +++++++++++++++++++ atom/browser/atom_browser_main_parts.h | 10 ++++++ atom/browser/lib/guest-view-manager.coffee | 13 +++++++- atom/browser/web_view_manager.cc | 15 +++++---- atom/browser/web_view_manager.h | 4 ++- 7 files changed, 74 insertions(+), 13 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 5b723801cd..da33451c1e 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -159,16 +159,20 @@ WebContents::WebContents(const mate::Dictionary& options) { type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW; - auto browser_context = AtomBrowserMainParts::Get()->browser_context(); content::WebContents* web_contents; if (is_guest) { - content::SiteInstance* site_instance = content::SiteInstance::CreateForURL( - browser_context, GURL("chrome-guest://fake-host")); + GURL guest_site; + options.Get("partition", &guest_site); + auto browser_context = + AtomBrowserMainParts::Get()->GetBrowserContextForPartition(guest_site); + auto site_instance = + content::SiteInstance::CreateForURL(browser_context, guest_site); content::WebContents::CreateParams params(browser_context, site_instance); guest_delegate_.reset(new WebViewGuestDelegate); params.guest_delegate = guest_delegate_.get(); web_contents = content::WebContents::Create(params); } else { + auto browser_context = AtomBrowserMainParts::Get()->browser_context(); content::WebContents::CreateParams params(browser_context); web_contents = content::WebContents::Create(params); } diff --git a/atom/browser/api/atom_api_web_view_manager.cc b/atom/browser/api/atom_api_web_view_manager.cc index d77ea18d6d..c69285a698 100644 --- a/atom/browser/api/atom_api_web_view_manager.cc +++ b/atom/browser/api/atom_api_web_view_manager.cc @@ -43,7 +43,8 @@ struct Converter { return options.Get("nodeIntegration", &(out->node_integration)) && options.Get("plugins", &(out->plugins)) && - options.Get("disableWebSecurity", &(out->disable_web_security)); + options.Get("disableWebSecurity", &(out->disable_web_security)) && + options.Get("partitionId", &(out->partition_id)); } }; diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index b4f61d0f19..189fc93869 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -26,6 +26,21 @@ namespace atom { +namespace { + +const base::FilePath::CharType kStoragePartitionDirName[] = "Partitions"; + +void GetStoragePartitionConfig(const GURL& partition, + base::FilePath* partition_path, + bool* in_memory, + std::string* id) { + *in_memory = (partition.path() != "/persist"); + *id = partition.query(); + *partition_path = base::FilePath(kStoragePartitionDirName).AppendASCII(*id); +} + +} // namespace + // static AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL; @@ -40,6 +55,7 @@ AtomBrowserMainParts::AtomBrowserMainParts() } AtomBrowserMainParts::~AtomBrowserMainParts() { + STLDeleteValues(&browser_context_map_); for (const auto& callback : destruction_callbacks_) callback.Run(); } @@ -50,6 +66,22 @@ AtomBrowserMainParts* AtomBrowserMainParts::Get() { return self_; } +content::BrowserContext* AtomBrowserMainParts::GetBrowserContextForPartition( + const GURL& partition) { + std::string id; + bool in_memory; + base::FilePath partition_path; + GetStoragePartitionConfig(partition, &partition_path, &in_memory, &id); + auto item = browser_context_map_.find(id); + if (item != browser_context_map_.end()) + return item->second; + + auto browser_context = CreateBrowserContext(); + browser_context->Initialize(partition_path, in_memory); + browser_context_map_[id] = browser_context; + return browser_context; +} + void AtomBrowserMainParts::RegisterDestructionCallback( const base::Closure& callback) { destruction_callbacks_.push_back(callback); diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index a2909cac53..993340bfb4 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -6,10 +6,13 @@ #define ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_ #include +#include +#include #include "base/callback.h" #include "base/timer/timer.h" #include "brightray/browser/browser_main_parts.h" +#include "content/public/browser/browser_context.h" class BrowserProcess; @@ -29,6 +32,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { static AtomBrowserMainParts* Get(); + // Returns the BrowserContext associated with the partition. + content::BrowserContext* GetBrowserContextForPartition( + const GURL& partition); + // Register a callback that should be destroyed before JavaScript environment // gets destroyed. void RegisterDestructionCallback(const base::Closure& callback); @@ -70,6 +77,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { // List of callbacks should be executed before destroying JS env. std::list destruction_callbacks_; + // partition_id => browser_context + std::map browser_context_map_; + static AtomBrowserMainParts* self_; DISALLOW_COPY_AND_ASSIGN(AtomBrowserMainParts); diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index 398cdb5d94..c0a87a7ac1 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -1,3 +1,4 @@ +crypto = require 'crypto' ipc = require 'ipc' webContents = require 'web-contents' webViewManager = null # Doesn't exist in early initialization. @@ -38,12 +39,21 @@ moveLastToFirst = (list) -> getNextInstanceId = (webContents) -> ++nextInstanceId +# Generate URL encoded partition id. +getPartitionId = (partition='default') -> + persist = partition.startsWith('persist:') + # Guest site url will be chrome-guest://fake-host/{persist}?{partitionId} + partitionId = "chrome-guest://fake-host/" + partitionId += if persist then 'persist?' else '?' + partitionId += crypto.createHash('sha256').update(partition).digest('hex') + # Create a new guest instance. createGuest = (embedder, params) -> webViewManager ?= process.atomBinding 'web_view_manager' id = getNextInstanceId embedder - guest = webContents.create {isGuest: true, embedder} + partitionId = getPartitionId params.partition + guest = webContents.create {isGuest: true, partition: partitionId, embedder} guestInstances[id] = {guest, embedder} # Destroy guest when the embedder is gone or navigated. @@ -120,6 +130,7 @@ attachGuest = (embedder, elementInstanceId, guestInstanceId, params) -> plugins: params.plugins disableWebSecurity: params.disablewebsecurity preloadUrl: params.preload ? '' + partitionId: getPartitionId(params.partition) guest.attachParams = params embedderElementsMap[key] = guestInstanceId diff --git a/atom/browser/web_view_manager.cc b/atom/browser/web_view_manager.cc index 7dba6c06dd..50e0723019 100644 --- a/atom/browser/web_view_manager.cc +++ b/atom/browser/web_view_manager.cc @@ -48,7 +48,7 @@ void WebViewManager::AddGuest(int guest_instance_id, content::WebContents* web_contents, const WebViewInfo& info) { base::AutoLock auto_lock(lock_); - web_contents_embdder_map_[guest_instance_id] = { web_contents, embedder }; + web_contents_embedder_map_[guest_instance_id] = { web_contents, embedder }; webview_info_map_[web_contents] = info; // Map the element in embedder to guest. @@ -59,11 +59,12 @@ void WebViewManager::AddGuest(int guest_instance_id, void WebViewManager::RemoveGuest(int guest_instance_id) { base::AutoLock auto_lock(lock_); - if (!ContainsKey(web_contents_embdder_map_, guest_instance_id)) + if (!ContainsKey(web_contents_embedder_map_, guest_instance_id)) return; - auto web_contents = web_contents_embdder_map_[guest_instance_id].web_contents; - web_contents_embdder_map_.erase(guest_instance_id); + auto web_contents = + web_contents_embedder_map_[guest_instance_id].web_contents; + web_contents_embedder_map_.erase(guest_instance_id); webview_info_map_.erase(web_contents); // Remove the record of element in embedder too. @@ -82,15 +83,15 @@ content::WebContents* WebViewManager::GetGuestByInstanceID( return nullptr; int guest_instance_id = element_instance_id_to_guest_map_[key]; - if (ContainsKey(web_contents_embdder_map_, guest_instance_id)) - return web_contents_embdder_map_[guest_instance_id].web_contents; + if (ContainsKey(web_contents_embedder_map_, guest_instance_id)) + return web_contents_embedder_map_[guest_instance_id].web_contents; else return nullptr; } bool WebViewManager::ForEachGuest(content::WebContents* embedder_web_contents, const GuestCallback& callback) { - for (auto& item : web_contents_embdder_map_) + for (auto& item : web_contents_embedder_map_) if (item.second.embedder == embedder_web_contents && callback.Run(item.second.web_contents)) return true; diff --git a/atom/browser/web_view_manager.h b/atom/browser/web_view_manager.h index b1bea92702..d8ed857b44 100644 --- a/atom/browser/web_view_manager.h +++ b/atom/browser/web_view_manager.h @@ -10,6 +10,7 @@ #include "base/files/file_path.h" #include "base/synchronization/lock.h" #include "content/public/browser/browser_plugin_guest_manager.h" +#include "content/public/browser/site_instance.h" namespace content { class BrowserContext; @@ -27,6 +28,7 @@ class WebViewManager : public content::BrowserPluginGuestManager { bool plugins; bool disable_web_security; base::FilePath preload_script; + GURL partition_id; }; // Finds the WebViewManager attached with |web_contents| and returns the @@ -57,7 +59,7 @@ class WebViewManager : public content::BrowserPluginGuestManager { content::WebContents* embedder; }; // guest_instance_id => (web_contents, embedder) - std::map web_contents_embdder_map_; + std::map web_contents_embedder_map_; struct ElementInstanceKey { int embedder_process_id; From 5189147021d9ca6d80c7cd53649b6a3b999dd7cb Mon Sep 17 00:00:00 2001 From: Robo Date: Thu, 27 Aug 2015 05:58:06 +0530 Subject: [PATCH 3/8] use embedders' browser context to retrieve webviewmanager --- atom/browser/web_view_manager.cc | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/atom/browser/web_view_manager.cc b/atom/browser/web_view_manager.cc index 50e0723019..76915264c6 100644 --- a/atom/browser/web_view_manager.cc +++ b/atom/browser/web_view_manager.cc @@ -5,27 +5,18 @@ #include "atom/browser/web_view_manager.h" #include "atom/browser/atom_browser_context.h" +#include "atom/browser/atom_browser_main_parts.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" namespace atom { -namespace { - -WebViewManager* GetManagerFromWebContents( - const content::WebContents* web_contents) { - auto context = web_contents->GetBrowserContext(); - if (!context) - return nullptr; - return static_cast(context->GetGuestManager()); -} - -} // namespace - // static bool WebViewManager::GetInfoForWebContents( const content::WebContents* web_contents, WebViewInfo* info) { - auto manager = GetManagerFromWebContents(web_contents); + // use embedders' browser context to retrieve WebViewManager. + auto manager = static_cast( + AtomBrowserMainParts::Get()->browser_context()->GetGuestManager()); if (!manager) return false; base::AutoLock auto_lock(manager->lock_); From 150b540e722c971a74304b303f2b16325b9477c5 Mon Sep 17 00:00:00 2001 From: Robo Date: Thu, 27 Aug 2015 06:57:03 +0530 Subject: [PATCH 4/8] add spec and docs --- docs/api/web-view-tag.md | 17 ++++++++++++++++ spec/fixtures/pages/partition/one.html | 5 +++++ spec/fixtures/pages/partition/two.html | 4 ++++ spec/webview-spec.coffee | 27 ++++++++++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 spec/fixtures/pages/partition/one.html create mode 100644 spec/fixtures/pages/partition/two.html diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index 6b64a0269c..ec85296552 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -131,6 +131,23 @@ page is loaded, use the `setUserAgent` method to change the user agent. If "on", the guest page will have web security disabled. +### partition + +```html + + +``` + +Sets the storage partition used by the `webview`. If the storage partition ID starts with `persist:`, +the `webview` will use a persistent storage partition available to all `webview` in the app with +the same storage partition ID. If the ID is unset or if there is no `persist:` prefix, the `webview` will +use an in-memory storage partition. By assigning the same partition ID, multiple `webview` +can share the same storage partition. + +This value can only be modified before the first navigation, since the storage partition of an active +renderer process cannot change. Subsequent attempts to modify the value will fail with a +DOM exception. + ## Methods The `webview` tag has the following methods: diff --git a/spec/fixtures/pages/partition/one.html b/spec/fixtures/pages/partition/one.html new file mode 100644 index 0000000000..765f721883 --- /dev/null +++ b/spec/fixtures/pages/partition/one.html @@ -0,0 +1,5 @@ + diff --git a/spec/fixtures/pages/partition/two.html b/spec/fixtures/pages/partition/two.html new file mode 100644 index 0000000000..ad22c341df --- /dev/null +++ b/spec/fixtures/pages/partition/two.html @@ -0,0 +1,4 @@ + diff --git a/spec/webview-spec.coffee b/spec/webview-spec.coffee index 6eb391ac94..ae8cd5d455 100644 --- a/spec/webview-spec.coffee +++ b/spec/webview-spec.coffee @@ -154,6 +154,33 @@ describe ' tag', -> webview.src = "data:text/html;base64,#{encoded}" document.body.appendChild webview + describe 'partition attribute', -> + isolatedWebview = null + beforeEach -> + isolatedWebview = new WebView + + afterEach -> + document.body.removeChild isolatedWebview + + it 'isolates storage for different id', (done) -> + listener = (e) -> + document.body.appendChild isolatedWebview + webview.removeEventListener 'did-finish-load', listener + listener2 = (e) -> + assert.equal e.message, "one 1" + webview.removeEventListener 'console-message', listener2 + listener3 = (e) -> + assert.equal e.message, " 0" + isolatedWebview.removeEventListener 'console-message', listener3 + done() + webview.addEventListener 'did-finish-load', listener + webview.addEventListener 'console-message', listener2 + webview.src = "file://#{fixtures}/pages/partition/one.html" + isolatedWebview.addEventListener 'console-message', listener3 + isolatedWebview.setAttribute 'partition', 'test' + isolatedWebview.src = "file://#{fixtures}/pages/partition/two.html" + document.body.appendChild webview + describe 'new-window event', -> it 'emits when window.open is called', (done) -> webview.addEventListener 'new-window', (e) -> From da5bac42f3efb9f28ed9dbb00747ba6052bc6250 Mon Sep 17 00:00:00 2001 From: Robo Date: Fri, 28 Aug 2015 13:00:50 +0530 Subject: [PATCH 5/8] use embedders' browser context when partition is not specified --- atom/browser/api/atom_api_web_contents.cc | 10 +++++++--- atom/browser/lib/guest-view-manager.coffee | 8 +++++--- docs/api/web-view-tag.md | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index da33451c1e..7cefe8e45e 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -159,12 +159,17 @@ WebContents::WebContents(const mate::Dictionary& options) { type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW; + content::BrowserContext* browser_context = + AtomBrowserMainParts::Get()->browser_context(); content::WebContents* web_contents; if (is_guest) { GURL guest_site; options.Get("partition", &guest_site); - auto browser_context = - AtomBrowserMainParts::Get()->GetBrowserContextForPartition(guest_site); + // use hosts' browser_context when no partition is specified. + if (!guest_site.query().empty()) { + browser_context = AtomBrowserMainParts::Get() + ->GetBrowserContextForPartition(guest_site); + } auto site_instance = content::SiteInstance::CreateForURL(browser_context, guest_site); content::WebContents::CreateParams params(browser_context, site_instance); @@ -172,7 +177,6 @@ WebContents::WebContents(const mate::Dictionary& options) { params.guest_delegate = guest_delegate_.get(); web_contents = content::WebContents::Create(params); } else { - auto browser_context = AtomBrowserMainParts::Get()->browser_context(); content::WebContents::CreateParams params(browser_context); web_contents = content::WebContents::Create(params); } diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index c0a87a7ac1..8d86e8fae9 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -40,12 +40,14 @@ getNextInstanceId = (webContents) -> ++nextInstanceId # Generate URL encoded partition id. -getPartitionId = (partition='default') -> +getPartitionId = (partition) -> persist = partition.startsWith('persist:') # Guest site url will be chrome-guest://fake-host/{persist}?{partitionId} partitionId = "chrome-guest://fake-host/" - partitionId += if persist then 'persist?' else '?' - partitionId += crypto.createHash('sha256').update(partition).digest('hex') + if partition + partitionId += if persist then 'persist?' else '?' + partitionId += crypto.createHash('sha256').update(partition).digest('hex') + return partitionId # Create a new guest instance. createGuest = (embedder, params) -> diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index ec85296552..cafcc5762e 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -140,7 +140,7 @@ If "on", the guest page will have web security disabled. Sets the storage partition used by the `webview`. If the storage partition ID starts with `persist:`, the `webview` will use a persistent storage partition available to all `webview` in the app with -the same storage partition ID. If the ID is unset or if there is no `persist:` prefix, the `webview` will +the same storage partition ID. if there is no `persist:` prefix, the `webview` will use an in-memory storage partition. By assigning the same partition ID, multiple `webview` can share the same storage partition. From 8f59c0b642b133a0df7bacd3a7a4c15b951ba259 Mon Sep 17 00:00:00 2001 From: Robo Date: Mon, 31 Aug 2015 23:53:31 +0530 Subject: [PATCH 6/8] create partitionId with encodedURIcomponent --- atom/browser/atom_browser_main_parts.cc | 22 +++++++-------- atom/browser/atom_browser_main_parts.h | 4 ++- atom/browser/lib/guest-view-manager.coffee | 11 +++++--- docs/api/web-view-tag.md | 3 +- spec/fixtures/pages/partition/one.html | 1 - spec/fixtures/pages/partition/two.html | 4 --- spec/webview-spec.coffee | 33 +++++++++------------- 7 files changed, 37 insertions(+), 41 deletions(-) delete mode 100644 spec/fixtures/pages/partition/two.html diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index 189fc93869..4463115cfe 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -28,15 +28,17 @@ namespace atom { namespace { -const base::FilePath::CharType kStoragePartitionDirName[] = "Partitions"; +const base::FilePath::CharType kStoragePartitionDirname[] = "Partitions"; void GetStoragePartitionConfig(const GURL& partition, base::FilePath* partition_path, bool* in_memory, std::string* id) { *in_memory = (partition.path() != "/persist"); - *id = partition.query(); - *partition_path = base::FilePath(kStoragePartitionDirName).AppendASCII(*id); + net::UnescapeRule::Type flags = + net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS; + *id = net::UnescapeURLComponent(partition.query(), flags); + *partition_path = base::FilePath(kStoragePartitionDirname).AppendASCII(*id); } } // namespace @@ -55,7 +57,6 @@ AtomBrowserMainParts::AtomBrowserMainParts() } AtomBrowserMainParts::~AtomBrowserMainParts() { - STLDeleteValues(&browser_context_map_); for (const auto& callback : destruction_callbacks_) callback.Run(); } @@ -72,14 +73,13 @@ content::BrowserContext* AtomBrowserMainParts::GetBrowserContextForPartition( bool in_memory; base::FilePath partition_path; GetStoragePartitionConfig(partition, &partition_path, &in_memory, &id); - auto item = browser_context_map_.find(id); - if (item != browser_context_map_.end()) - return item->second; + if (browser_context_map_.contains(id)) + return browser_context_map_.get(id); - auto browser_context = CreateBrowserContext(); - browser_context->Initialize(partition_path, in_memory); - browser_context_map_[id] = browser_context; - return browser_context; + scoped_ptr browser_context(CreateBrowserContext()); + browser_context->Initialize(partition_path.value(), in_memory); + browser_context_map_.set(id, browser_context.Pass()); + return browser_context_map_.get(id); } void AtomBrowserMainParts::RegisterDestructionCallback( diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index 993340bfb4..d952f43288 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -10,6 +10,7 @@ #include #include "base/callback.h" +#include "base/containers/scoped_ptr_hash_map.h" #include "base/timer/timer.h" #include "brightray/browser/browser_main_parts.h" #include "content/public/browser/browser_context.h" @@ -78,7 +79,8 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { std::list destruction_callbacks_; // partition_id => browser_context - std::map browser_context_map_; + base::ScopedPtrHashMap> + browser_context_map_; static AtomBrowserMainParts* self_; diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index 8d86e8fae9..2f1c831215 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -1,4 +1,3 @@ -crypto = require 'crypto' ipc = require 'ipc' webContents = require 'web-contents' webViewManager = null # Doesn't exist in early initialization. @@ -41,12 +40,16 @@ getNextInstanceId = (webContents) -> # Generate URL encoded partition id. getPartitionId = (partition) -> - persist = partition.startsWith('persist:') # Guest site url will be chrome-guest://fake-host/{persist}?{partitionId} partitionId = "chrome-guest://fake-host/" if partition - partitionId += if persist then 'persist?' else '?' - partitionId += crypto.createHash('sha256').update(partition).digest('hex') + persist = partition.startsWith('persist:') + if persist + partition = partition.substring('persist:'.length) + partitionId += 'persist?' + else + partitionId += '?' + partitionId += encodeURIComponent(partition) return partitionId # Create a new guest instance. diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index cafcc5762e..c1b1f705e9 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -142,7 +142,8 @@ Sets the storage partition used by the `webview`. If the storage partition ID st the `webview` will use a persistent storage partition available to all `webview` in the app with the same storage partition ID. if there is no `persist:` prefix, the `webview` will use an in-memory storage partition. By assigning the same partition ID, multiple `webview` -can share the same storage partition. +can share the same storage partition. If the storage partition ID is unset then default storage +of the app will be used. This value can only be modified before the first navigation, since the storage partition of an active renderer process cannot change. Subsequent attempts to modify the value will fail with a diff --git a/spec/fixtures/pages/partition/one.html b/spec/fixtures/pages/partition/one.html index 765f721883..ad22c341df 100644 --- a/spec/fixtures/pages/partition/one.html +++ b/spec/fixtures/pages/partition/one.html @@ -1,5 +1,4 @@ diff --git a/spec/fixtures/pages/partition/two.html b/spec/fixtures/pages/partition/two.html deleted file mode 100644 index ad22c341df..0000000000 --- a/spec/fixtures/pages/partition/two.html +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/spec/webview-spec.coffee b/spec/webview-spec.coffee index ae8cd5d455..486efaa6ff 100644 --- a/spec/webview-spec.coffee +++ b/spec/webview-spec.coffee @@ -155,30 +155,25 @@ describe ' tag', -> document.body.appendChild webview describe 'partition attribute', -> - isolatedWebview = null - beforeEach -> - isolatedWebview = new WebView - - afterEach -> - document.body.removeChild isolatedWebview - it 'isolates storage for different id', (done) -> listener = (e) -> - document.body.appendChild isolatedWebview - webview.removeEventListener 'did-finish-load', listener - listener2 = (e) -> - assert.equal e.message, "one 1" - webview.removeEventListener 'console-message', listener2 - listener3 = (e) -> assert.equal e.message, " 0" - isolatedWebview.removeEventListener 'console-message', listener3 + webview.removeEventListener 'console-message', listener done() - webview.addEventListener 'did-finish-load', listener - webview.addEventListener 'console-message', listener2 + window.localStorage.setItem 'test', 'one' + webview.addEventListener 'console-message', listener + webview.src = "file://#{fixtures}/pages/partition/one.html" + webview.partition = "test" + document.body.appendChild webview + + it 'uses current session storage when no id is provided', (done) -> + listener = (e) -> + assert.equal e.message, "one 1" + webview.removeEventListener 'console-message', listener + done() + window.localStorage.setItem 'test', 'one' + webview.addEventListener 'console-message', listener webview.src = "file://#{fixtures}/pages/partition/one.html" - isolatedWebview.addEventListener 'console-message', listener3 - isolatedWebview.setAttribute 'partition', 'test' - isolatedWebview.src = "file://#{fixtures}/pages/partition/two.html" document.body.appendChild webview describe 'new-window event', -> From 03ba9533fbfbce42e1770c581b04fde9fcec4856 Mon Sep 17 00:00:00 2001 From: Robo Date: Thu, 3 Sep 2015 06:17:58 +0530 Subject: [PATCH 7/8] store webviewinfo as web contents userdata --- atom/browser/api/atom_api_web_view_manager.cc | 26 +++++++++++------- atom/browser/atom_browser_client.cc | 14 +++++++--- atom/browser/lib/guest-view-manager.coffee | 2 ++ atom/browser/web_view_constants.cc | 24 +++++++++++++++++ atom/browser/web_view_constants.h | 27 +++++++++++++++++++ atom/browser/web_view_guest_delegate.cc | 10 ++----- atom/browser/web_view_manager.cc | 23 +--------------- atom/browser/web_view_manager.h | 23 +++++++++------- filenames.gypi | 2 ++ spec/webview-spec.coffee | 17 ++++++++++++ 10 files changed, 114 insertions(+), 54 deletions(-) create mode 100644 atom/browser/web_view_constants.cc create mode 100644 atom/browser/web_view_constants.h diff --git a/atom/browser/api/atom_api_web_view_manager.cc b/atom/browser/api/atom_api_web_view_manager.cc index c69285a698..221d0d7118 100644 --- a/atom/browser/api/atom_api_web_view_manager.cc +++ b/atom/browser/api/atom_api_web_view_manager.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "atom/browser/api/atom_api_web_contents.h" +#include "atom/browser/web_view_constants.h" #include "atom/browser/web_view_manager.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "content/public/browser/browser_context.h" @@ -34,17 +35,19 @@ struct Converter { return false; GURL preload_url; - if (!options.Get("preloadUrl", &preload_url)) + if (!options.Get(atom::web_view::kPreloadUrl, &preload_url)) return false; if (!preload_url.is_empty() && !net::FileURLToFilePath(preload_url, &(out->preload_script))) return false; - return options.Get("nodeIntegration", &(out->node_integration)) && - options.Get("plugins", &(out->plugins)) && - options.Get("disableWebSecurity", &(out->disable_web_security)) && - options.Get("partitionId", &(out->partition_id)); + return options.Get(atom::web_view::kNodeIntegration, + &(out->node_integration)) && + options.Get(atom::web_view::kPlugins, &(out->plugins)) && + options.Get(atom::web_view::kPartitionId, &(out->partition_id)) && + options.Get(atom::web_view::kDisableWebSecurity, + &(out->disable_web_security)); } }; @@ -68,12 +71,15 @@ void AddGuest(int guest_instance_id, content::WebContents* guest_web_contents, atom::WebViewManager::WebViewInfo info) { auto manager = GetWebViewManager(embedder); - if (manager) { - info.guest_instance_id = guest_instance_id; - info.embedder = embedder; + if (manager) manager->AddGuest(guest_instance_id, element_instance_id, embedder, - guest_web_contents, info); - } + guest_web_contents); + + info.guest_instance_id = guest_instance_id; + info.embedder = embedder; + auto data = new atom::WebViewManager::WebViewInfoUserData(info); + guest_web_contents->SetUserData( + atom::web_view::kWebViewInfoKeyName, data); } void RemoveGuest(content::WebContents* embedder, int guest_instance_id) { diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 8db71fd303..fad952d533 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -16,6 +16,7 @@ #include "atom/browser/browser.h" #include "atom/browser/native_window.h" #include "atom/browser/web_view_manager.h" +#include "atom/browser/web_view_constants.h" #include "atom/browser/window_list.h" #include "atom/common/options_switches.h" #include "base/command_line.h" @@ -74,8 +75,12 @@ ProcessOwner GetProcessOwner(int process_id, return OWNER_NATIVE_WINDOW; // Then search for guest WebContents. - if (WebViewManager::GetInfoForWebContents(web_contents, info)) + auto data = static_cast( + web_contents->GetUserData(web_view::kWebViewInfoKeyName)); + if (data) { + *info = data->web_view_info(); return OWNER_GUEST_WEB_CONTENTS; + } return OWNER_NONE; } @@ -155,9 +160,10 @@ void AtomBrowserClient::OverrideWebkitPrefs( // Custom preferences of guest page. auto web_contents = content::WebContents::FromRenderViewHost(host); - WebViewManager::WebViewInfo info; - if (WebViewManager::GetInfoForWebContents(web_contents, &info)) { - prefs->web_security_enabled = !info.disable_web_security; + auto info = static_cast( + web_contents->GetUserData(web_view::kWebViewInfoKeyName)); + if (info) { + prefs->web_security_enabled = !info->web_view_info().disable_web_security; return; } diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index 2f1c831215..5812746990 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -48,6 +48,8 @@ getPartitionId = (partition) -> partition = partition.substring('persist:'.length) partitionId += 'persist?' else + # Just to differentiate from same persistant ID + partition += "_temp" partitionId += '?' partitionId += encodeURIComponent(partition) return partitionId diff --git a/atom/browser/web_view_constants.cc b/atom/browser/web_view_constants.cc new file mode 100644 index 0000000000..6f8314cbcf --- /dev/null +++ b/atom/browser/web_view_constants.cc @@ -0,0 +1,24 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/web_view_constants.h" + +namespace atom { + +namespace web_view { + +const char kPreloadUrl[] = "preloadUrl"; +const char kNodeIntegration[] = "nodeIntegration"; +const char kPlugins[] = "plugins"; +const char kDisableWebSecurity[] = "disableWebSecurity"; +const char kPartitionId[] = "partitionId"; + +const int kDefaultWidth = 300; +const int kDefaultHeight = 300; + +const char kWebViewInfoKeyName[] = "web_view_info"; + +} // namespace web_view + +} // namespace atom diff --git a/atom/browser/web_view_constants.h b/atom/browser/web_view_constants.h new file mode 100644 index 0000000000..0831bdbdf1 --- /dev/null +++ b/atom/browser/web_view_constants.h @@ -0,0 +1,27 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_WEB_VIEW_CONSTANTS_H_ +#define ATOM_BROWSER_WEB_VIEW_CONSTANTS_H_ + +namespace atom { + +namespace web_view { + +extern const char kPreloadUrl[]; +extern const char kNodeIntegration[]; +extern const char kPlugins[]; +extern const char kDisableWebSecurity[]; +extern const char kPartitionId[]; + +extern const int kDefaultWidth; +extern const int kDefaultHeight; + +extern const char kWebViewInfoKeyName[]; + +} // namespace web_view + +} // namespace atom + +#endif // ATOM_BROWSER_WEB_VIEW_CONSTANTS_H_ diff --git a/atom/browser/web_view_guest_delegate.cc b/atom/browser/web_view_guest_delegate.cc index 8e1810c4a3..a954cea8dc 100644 --- a/atom/browser/web_view_guest_delegate.cc +++ b/atom/browser/web_view_guest_delegate.cc @@ -5,6 +5,7 @@ #include "atom/browser/web_view_guest_delegate.h" #include "atom/browser/api/atom_api_web_contents.h" +#include "atom/browser/web_view_constants.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "content/public/browser/guest_host.h" #include "content/public/browser/render_frame_host.h" @@ -13,13 +14,6 @@ namespace atom { -namespace { - -const int kDefaultWidth = 300; -const int kDefaultHeight = 300; - -} // namespace - WebViewGuestDelegate::WebViewGuestDelegate() : guest_opaque_(true), guest_host_(nullptr), @@ -178,7 +172,7 @@ gfx::Size WebViewGuestDelegate::GetDefaultSize() const { return embedder_web_contents_->GetRenderWidgetHostView() ->GetVisibleViewportSize(); } else { - return gfx::Size(kDefaultWidth, kDefaultHeight); + return gfx::Size(web_view::kDefaultWidth, web_view::kDefaultHeight); } } diff --git a/atom/browser/web_view_manager.cc b/atom/browser/web_view_manager.cc index 76915264c6..9d0b933759 100644 --- a/atom/browser/web_view_manager.cc +++ b/atom/browser/web_view_manager.cc @@ -11,22 +11,6 @@ namespace atom { -// static -bool WebViewManager::GetInfoForWebContents( - const content::WebContents* web_contents, WebViewInfo* info) { - // use embedders' browser context to retrieve WebViewManager. - auto manager = static_cast( - AtomBrowserMainParts::Get()->browser_context()->GetGuestManager()); - if (!manager) - return false; - base::AutoLock auto_lock(manager->lock_); - auto iter = manager->webview_info_map_.find(web_contents); - if (iter == manager->webview_info_map_.end()) - return false; - *info = iter->second; - return true; -} - WebViewManager::WebViewManager(content::BrowserContext* context) { } @@ -36,11 +20,9 @@ WebViewManager::~WebViewManager() { void WebViewManager::AddGuest(int guest_instance_id, int element_instance_id, content::WebContents* embedder, - content::WebContents* web_contents, - const WebViewInfo& info) { + content::WebContents* web_contents) { base::AutoLock auto_lock(lock_); web_contents_embedder_map_[guest_instance_id] = { web_contents, embedder }; - webview_info_map_[web_contents] = info; // Map the element in embedder to guest. int owner_process_id = embedder->GetRenderProcessHost()->GetID(); @@ -53,10 +35,7 @@ void WebViewManager::RemoveGuest(int guest_instance_id) { if (!ContainsKey(web_contents_embedder_map_, guest_instance_id)) return; - auto web_contents = - web_contents_embedder_map_[guest_instance_id].web_contents; web_contents_embedder_map_.erase(guest_instance_id); - webview_info_map_.erase(web_contents); // Remove the record of element in embedder too. for (const auto& element : element_instance_id_to_guest_map_) diff --git a/atom/browser/web_view_manager.h b/atom/browser/web_view_manager.h index d8ed857b44..20c0448497 100644 --- a/atom/browser/web_view_manager.h +++ b/atom/browser/web_view_manager.h @@ -8,6 +8,7 @@ #include #include "base/files/file_path.h" +#include "base/supports_user_data.h" #include "base/synchronization/lock.h" #include "content/public/browser/browser_plugin_guest_manager.h" #include "content/public/browser/site_instance.h" @@ -31,10 +32,17 @@ class WebViewManager : public content::BrowserPluginGuestManager { GURL partition_id; }; - // Finds the WebViewManager attached with |web_contents| and returns the - // WebViewInfo of it. - static bool GetInfoForWebContents(const content::WebContents* web_contents, - WebViewInfo* info); + class WebViewInfoUserData : public base::SupportsUserData::Data { + public: + explicit WebViewInfoUserData(WebViewInfo info) + : web_view_info_(info) {} + ~WebViewInfoUserData() override {} + + WebViewInfo& web_view_info() { return web_view_info_; } + + private: + WebViewInfo web_view_info_; + }; explicit WebViewManager(content::BrowserContext* context); virtual ~WebViewManager(); @@ -42,8 +50,7 @@ class WebViewManager : public content::BrowserPluginGuestManager { void AddGuest(int guest_instance_id, int element_instance_id, content::WebContents* embedder, - content::WebContents* web_contents, - const WebViewInfo& info); + content::WebContents* web_contents); void RemoveGuest(int guest_instance_id); protected: @@ -83,10 +90,6 @@ class WebViewManager : public content::BrowserPluginGuestManager { // (embedder_process_id, element_instance_id) => guest_instance_id std::map element_instance_id_to_guest_map_; - typedef std::map WebViewInfoMap; - // web_contents => (guest_instance_id, embedder, ...) - WebViewInfoMap webview_info_map_; - base::Lock lock_; DISALLOW_COPY_AND_ASSIGN(WebViewManager); diff --git a/filenames.gypi b/filenames.gypi index 807ccd32bb..2f97d01507 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -226,6 +226,8 @@ 'atom/browser/ui/x/window_state_watcher.h', 'atom/browser/ui/x/x_window_utils.cc', 'atom/browser/ui/x/x_window_utils.h', + 'atom/browser/web_view_constants.cc', + 'atom/browser/web_view_constants.h', 'atom/browser/web_view_guest_delegate.cc', 'atom/browser/web_view_guest_delegate.h', 'atom/browser/web_view_manager.cc', diff --git a/spec/webview-spec.coffee b/spec/webview-spec.coffee index 486efaa6ff..fe281510b4 100644 --- a/spec/webview-spec.coffee +++ b/spec/webview-spec.coffee @@ -155,6 +155,23 @@ describe ' tag', -> document.body.appendChild webview describe 'partition attribute', -> + it 'inserts no node symbols when not set', (done) -> + webview.addEventListener 'console-message', (e) -> + assert.equal e.message, 'undefined undefined undefined undefined' + done() + webview.src = "file://#{fixtures}/pages/c.html" + webview.partition = "test" + document.body.appendChild webview + + it 'inserts node symbols when set', (done) -> + webview.addEventListener 'console-message', (e) -> + assert.equal e.message, 'function object object' + done() + webview.setAttribute 'nodeintegration', 'on' + webview.src = "file://#{fixtures}/pages/d.html" + webview.partition = "test" + document.body.appendChild webview + it 'isolates storage for different id', (done) -> listener = (e) -> assert.equal e.message, " 0" From f1e5a99881336115149c94a6274dfa05b9f70b0b Mon Sep 17 00:00:00 2001 From: Calvin Jeng Date: Fri, 4 Sep 2015 00:06:50 +0800 Subject: [PATCH 8/8] zh-tw translation --- .../zh-TW/tutorial/online-offline-events.md | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 docs-translations/zh-TW/tutorial/online-offline-events.md diff --git a/docs-translations/zh-TW/tutorial/online-offline-events.md b/docs-translations/zh-TW/tutorial/online-offline-events.md new file mode 100644 index 0000000000..a4366f88a0 --- /dev/null +++ b/docs-translations/zh-TW/tutorial/online-offline-events.md @@ -0,0 +1,80 @@ +# 在線/離線事件偵測 + +我們可以在渲染引擎 (renderer) 的行程裡用標準的 HTML5 API 來實作在線與離線事件的偵測。 +請參考以下範例: + +_main.js_ + +```javascript +var app = require('app'); +var BrowserWindow = require('browser-window'); +var onlineStatusWindow; + +app.on('ready', function() { + onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); + onlineStatusWindow.loadUrl('file://' + __dirname + '/online-status.html'); +}); +``` + +_online-status.html_ + +```html + + + + + + +``` + +您也許有時候也會有想要在主行程裡回應這些事件的情況。然而,在主行程裡並沒有 `navigator` 這個物件,因此不能直接地偵測這些事件。 +但我們可以使用 Electron 所提供的跨行程 (inter-process) 溝通的工具,事件就可以被傳送到主程序內並做您所需的處理。 +請參考以下範例: + +_main.js_ + +```javascript +var app = require('app'); +var ipc = require('ipc'); +var BrowserWindow = require('browser-window'); +var onlineStatusWindow; + +app.on('ready', function() { + onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); + onlineStatusWindow.loadUrl('file://' + __dirname + '/online-status.html'); +}); + +ipc.on('online-status-changed', function(event, status) { + console.log(status); +}); +``` + +_online-status.html_ + +```html + + + + + + +```