diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 21a553e4d1d5..bd49f9fddc05 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -19,7 +19,7 @@ #include "atom/browser/browser.h" #include "atom/browser/login_handler.h" #include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/content_converter.h" +#include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/node_includes.h" #include "atom/common/options_switches.h" diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc index f6cc6d796557..e76f26f0d4f5 100644 --- a/atom/browser/api/atom_api_protocol.cc +++ b/atom/browser/api/atom_api_protocol.cc @@ -12,7 +12,7 @@ #include "atom/browser/net/url_request_fetch_job.h" #include "atom/browser/net/url_request_string_job.h" #include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/content_converter.h" +#include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/node_includes.h" #include "native_mate/dictionary.h" diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 900c3e65a376..fa40296f57d8 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -18,6 +18,7 @@ #include "atom/common/api/event_emitter_caller.h" #include "atom/common/native_mate_converters/blink_converter.h" #include "atom/common/native_mate_converters/callback.h" +#include "atom/common/native_mate_converters/content_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h" @@ -404,6 +405,12 @@ void WebContents::RendererResponsive(content::WebContents* source) { owner_window()->RendererResponsive(source); } +bool WebContents::HandleContextMenu(const content::ContextMenuParams& params) { + context_menu_context_ = params.custom_context; + Emit("-context-menu", params); + return true; +} + void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) { // Do nothing, we override this method just to avoid compilation error since // there are two virtual functions named BeforeUnloadFired. @@ -840,6 +847,15 @@ void WebContents::RemoveWorkSpace(mate::Arguments* args, DevToolsRemoveFileSystem(path); } +void WebContents::ExecuteContextMenuCommand(int action) { + web_contents()->ExecuteCustomContextMenuCommand(action, + context_menu_context_); +} + +void WebContents::NotifyContextMenuClosed() { + web_contents()->NotifyContextMenuClosed(context_menu_context_); +} + void WebContents::Undo() { web_contents()->Undo(); } @@ -1051,6 +1067,10 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( .SetMethod("_printToPDF", &WebContents::PrintToPDF) .SetMethod("addWorkSpace", &WebContents::AddWorkSpace) .SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace) + .SetMethod("_executeContextMenuCommand", + &WebContents::ExecuteContextMenuCommand) + .SetMethod("_notifyContextMenuClosed", + &WebContents::NotifyContextMenuClosed) .SetProperty("session", &WebContents::Session, true) .SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents, true) diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 7fa8951106b2..5a55ad2abd7a 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -13,6 +13,7 @@ #include "atom/browser/api/trackable_object.h" #include "atom/browser/common_web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" +#include "content/public/common/context_menu_params.h" #include "content/public/common/favicon_url.h" #include "native_mate/handle.h" #include "ui/gfx/image/image.h" @@ -92,6 +93,8 @@ class WebContents : public mate::TrackableObject, void SetAudioMuted(bool muted); bool IsAudioMuted(); void Print(mate::Arguments* args); + void ExecuteContextMenuCommand(int action); + void NotifyContextMenuClosed(); // Print current page as PDF. void PrintToPDF(const base::DictionaryValue& setting, @@ -189,6 +192,7 @@ class WebContents : public mate::TrackableObject, void ExitFullscreenModeForTab(content::WebContents* source) override; void RendererUnresponsive(content::WebContents* source) override; void RendererResponsive(content::WebContents* source) override; + bool HandleContextMenu(const content::ContextMenuParams& params) override; // content::WebContentsObserver: void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; @@ -255,6 +259,9 @@ class WebContents : public mate::TrackableObject, // embedders' zoom level change. void OnZoomLevelChanged(double level); + // Recent unhandled context menu context. + content::CustomContextMenuContext context_menu_context_; + v8::Global session_; v8::Global devtools_web_contents_; diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee index 3a2abfb5155f..afe70323f0a5 100644 --- a/atom/browser/api/lib/web-contents.coffee +++ b/atom/browser/api/lib/web-contents.coffee @@ -1,4 +1,5 @@ EventEmitter = require('events').EventEmitter +Menu = require './menu' NavigationController = require './navigation-controller' binding = process.atomBinding 'web_contents' ipc = require 'ipc' @@ -34,6 +35,36 @@ PDFPageSize = width_microns: 279400 custom_display_name: "Tabloid" +clickHandler = (action) -> + @_executeContextMenuCommand action + +convertToMenuTemplate = (items, handler) -> + template = [] + for item in items + do (item) -> + transformed = + if item.type is 'submenu' + type: 'submenu' + label: item.label + enabled: item.enabled + submenu: convertToMenuTemplate item.subItems, handler + else if item.type is 'separator' + type: 'separator' + else if item.type is 'checkbox' + type: 'checkbox' + label: item.label + enabled: item.enabled + checked: item.checked + else + type: 'normal' + label: item.label + enabled: item.enabled + if item.id? + transformed.click = -> + handler item.id + template.push transformed + template + wrapWebContents = (webContents) -> # webContents is an EventEmitter. webContents.__proto__ = EventEmitter.prototype @@ -65,6 +96,16 @@ wrapWebContents = (webContents) -> Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value) ipc.emit channel, event, args... + # Handle context menu action request from renderer widget. + webContents.on '-context-menu', (event, params) -> + if params.isPepperMenu + template = convertToMenuTemplate(params.menuItems, clickHandler.bind(webContents)) + menu = Menu.buildFromTemplate template + # The menu is expected to show asynchronously. + setImmediate -> + menu.popup params.x, params.y + webContents._notifyContextMenuClosed() + webContents.printToPDF = (options, callback) -> printingSetting = pageRage: [] diff --git a/atom/common/native_mate_converters/content_converter.cc b/atom/common/native_mate_converters/content_converter.cc index b6f3a2c1cc03..2318e7d8e837 100644 --- a/atom/common/native_mate_converters/content_converter.cc +++ b/atom/common/native_mate_converters/content_converter.cc @@ -4,30 +4,50 @@ #include "atom/common/native_mate_converters/content_converter.h" +#include "atom/common/native_mate_converters/string16_converter.h" +#include "content/public/common/context_menu_params.h" +#include "content/public/common/menu_item.h" #include "native_mate/dictionary.h" -#include "net/url_request/url_request.h" namespace mate { +template<> +struct Converter { + static v8::Local ToV8(v8::Isolate* isolate, + const content::MenuItem::Type& val) { + switch (val) { + case content::MenuItem::CHECKABLE_OPTION: + return StringToV8(isolate, "checkbox"); + case content::MenuItem::SEPARATOR: + return StringToV8(isolate, "separator"); + case content::MenuItem::SUBMENU: + return StringToV8(isolate, "submenu"); + default: + return StringToV8(isolate, "normal"); + } + } +}; + // static -v8::Local Converter::ToV8( - v8::Isolate* isolate, const net::URLRequest* val) { +v8::Local Converter::ToV8( + v8::Isolate* isolate, const content::MenuItem& val) { mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("method", val->method()); - dict.Set("url", val->url().spec()); - dict.Set("referrer", val->referrer()); + dict.Set("id", val.action); + dict.Set("type", val.type); + dict.Set("label", val.label); + dict.Set("enabled", val.enabled); + dict.Set("checked", val.checked); return mate::ConvertToV8(isolate, dict); } // static -v8::Local Converter::ToV8( - v8::Isolate* isolate, const net::AuthChallengeInfo* val) { +v8::Local Converter::ToV8( + v8::Isolate* isolate, const content::ContextMenuParams& val) { mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("isProxy", val->is_proxy); - dict.Set("scheme", val->scheme); - dict.Set("host", val->challenger.host()); - dict.Set("port", static_cast(val->challenger.port())); - dict.Set("realm", val->realm); + dict.Set("x", val.x); + dict.Set("y", val.y); + dict.Set("isPepperMenu", val.custom_context.is_pepper_menu); + dict.Set("menuItems", val.custom_items); return mate::ConvertToV8(isolate, dict); } diff --git a/atom/common/native_mate_converters/content_converter.h b/atom/common/native_mate_converters/content_converter.h index 0d4d5fe2cce0..5cca2b38b251 100644 --- a/atom/common/native_mate_converters/content_converter.h +++ b/atom/common/native_mate_converters/content_converter.h @@ -7,23 +7,23 @@ #include "native_mate/converter.h" -namespace net { -class AuthChallengeInfo; -class URLRequest; +namespace content { +struct ContextMenuParams; +struct MenuItem; } namespace mate { template<> -struct Converter { +struct Converter { static v8::Local ToV8(v8::Isolate* isolate, - const net::URLRequest* val); + const content::MenuItem& val); }; template<> -struct Converter { +struct Converter { static v8::Local ToV8(v8::Isolate* isolate, - const net::AuthChallengeInfo* val); + const content::ContextMenuParams& val); }; } // namespace mate diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc new file mode 100644 index 000000000000..4796d962660a --- /dev/null +++ b/atom/common/native_mate_converters/net_converter.cc @@ -0,0 +1,34 @@ +// 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/common/native_mate_converters/net_converter.h" + +#include "native_mate/dictionary.h" +#include "net/url_request/url_request.h" + +namespace mate { + +// static +v8::Local Converter::ToV8( + v8::Isolate* isolate, const net::URLRequest* val) { + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.Set("method", val->method()); + dict.Set("url", val->url().spec()); + dict.Set("referrer", val->referrer()); + return mate::ConvertToV8(isolate, dict); +} + +// static +v8::Local Converter::ToV8( + v8::Isolate* isolate, const net::AuthChallengeInfo* val) { + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.Set("isProxy", val->is_proxy); + dict.Set("scheme", val->scheme); + dict.Set("host", val->challenger.host()); + dict.Set("port", static_cast(val->challenger.port())); + dict.Set("realm", val->realm); + return mate::ConvertToV8(isolate, dict); +} + +} // namespace mate diff --git a/atom/common/native_mate_converters/net_converter.h b/atom/common/native_mate_converters/net_converter.h new file mode 100644 index 000000000000..352c613eaabb --- /dev/null +++ b/atom/common/native_mate_converters/net_converter.h @@ -0,0 +1,31 @@ +// 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_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_ +#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_ + +#include "native_mate/converter.h" + +namespace net { +class AuthChallengeInfo; +class URLRequest; +} + +namespace mate { + +template<> +struct Converter { + static v8::Local ToV8(v8::Isolate* isolate, + const net::URLRequest* val); +}; + +template<> +struct Converter { + static v8::Local ToV8(v8::Isolate* isolate, + const net::AuthChallengeInfo* val); +}; + +} // namespace mate + +#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_ diff --git a/filenames.gypi b/filenames.gypi index ba739764f492..0e70347309c0 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -316,6 +316,8 @@ 'atom/common/native_mate_converters/gurl_converter.h', 'atom/common/native_mate_converters/image_converter.cc', 'atom/common/native_mate_converters/image_converter.h', + 'atom/common/native_mate_converters/net_converter.cc', + 'atom/common/native_mate_converters/net_converter.h', 'atom/common/native_mate_converters/string16_converter.h', 'atom/common/native_mate_converters/v8_value_converter.cc', 'atom/common/native_mate_converters/v8_value_converter.h',