Merge pull request #7540 from deepak1556/form_post_new_window_patch
webContents: handle POST navigation for new windows
This commit is contained in:
		
				commit
				
					
						4867475cee
					
				
			
		
					 18 changed files with 321 additions and 65 deletions
				
			
		| 
						 | 
					@ -528,10 +528,12 @@ void App::OnLogin(LoginHandler* login_handler,
 | 
				
			||||||
    login_handler->CancelAuth();
 | 
					    login_handler->CancelAuth();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void App::OnCreateWindow(const GURL& target_url,
 | 
					void App::OnCreateWindow(
 | 
				
			||||||
 | 
					    const GURL& target_url,
 | 
				
			||||||
    const std::string& frame_name,
 | 
					    const std::string& frame_name,
 | 
				
			||||||
    WindowOpenDisposition disposition,
 | 
					    WindowOpenDisposition disposition,
 | 
				
			||||||
    const std::vector<base::string16>& features,
 | 
					    const std::vector<base::string16>& features,
 | 
				
			||||||
 | 
					    const scoped_refptr<content::ResourceRequestBodyImpl>& body,
 | 
				
			||||||
    int render_process_id,
 | 
					    int render_process_id,
 | 
				
			||||||
    int render_frame_id) {
 | 
					    int render_frame_id) {
 | 
				
			||||||
  v8::Locker locker(isolate());
 | 
					  v8::Locker locker(isolate());
 | 
				
			||||||
| 
						 | 
					@ -545,7 +547,8 @@ void App::OnCreateWindow(const GURL& target_url,
 | 
				
			||||||
    api_web_contents->OnCreateWindow(target_url,
 | 
					    api_web_contents->OnCreateWindow(target_url,
 | 
				
			||||||
                                     frame_name,
 | 
					                                     frame_name,
 | 
				
			||||||
                                     disposition,
 | 
					                                     disposition,
 | 
				
			||||||
                                     features);
 | 
					                                     features,
 | 
				
			||||||
 | 
					                                     body);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,10 +48,12 @@ class App : public AtomBrowserClient::Delegate,
 | 
				
			||||||
                             v8::Local<v8::FunctionTemplate> prototype);
 | 
					                             v8::Local<v8::FunctionTemplate> prototype);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Called when window with disposition needs to be created.
 | 
					  // Called when window with disposition needs to be created.
 | 
				
			||||||
  void OnCreateWindow(const GURL& target_url,
 | 
					  void OnCreateWindow(
 | 
				
			||||||
 | 
					      const GURL& target_url,
 | 
				
			||||||
      const std::string& frame_name,
 | 
					      const std::string& frame_name,
 | 
				
			||||||
      WindowOpenDisposition disposition,
 | 
					      WindowOpenDisposition disposition,
 | 
				
			||||||
      const std::vector<base::string16>& features,
 | 
					      const std::vector<base::string16>& features,
 | 
				
			||||||
 | 
					      const scoped_refptr<content::ResourceRequestBodyImpl>& body,
 | 
				
			||||||
      int render_process_id,
 | 
					      int render_process_id,
 | 
				
			||||||
      int render_frame_id);
 | 
					      int render_frame_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -387,12 +387,14 @@ bool WebContents::AddMessageToConsole(content::WebContents* source,
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void WebContents::OnCreateWindow(const GURL& target_url,
 | 
					void WebContents::OnCreateWindow(
 | 
				
			||||||
 | 
					    const GURL& target_url,
 | 
				
			||||||
    const std::string& frame_name,
 | 
					    const std::string& frame_name,
 | 
				
			||||||
    WindowOpenDisposition disposition,
 | 
					    WindowOpenDisposition disposition,
 | 
				
			||||||
                                 const std::vector<base::string16>& features) {
 | 
					    const std::vector<base::string16>& features,
 | 
				
			||||||
 | 
					    const scoped_refptr<content::ResourceRequestBodyImpl>& body) {
 | 
				
			||||||
  if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
 | 
					  if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN)
 | 
				
			||||||
    Emit("-new-window", target_url, frame_name, disposition, features);
 | 
					    Emit("-new-window", target_url, frame_name, disposition, features, body);
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    Emit("new-window", target_url, frame_name, disposition, features);
 | 
					    Emit("new-window", target_url, frame_name, disposition, features);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -855,6 +857,12 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
 | 
				
			||||||
  if (options.Get("extraHeaders", &extra_headers))
 | 
					  if (options.Get("extraHeaders", &extra_headers))
 | 
				
			||||||
    params.extra_headers = extra_headers;
 | 
					    params.extra_headers = extra_headers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  scoped_refptr<content::ResourceRequestBodyImpl> body;
 | 
				
			||||||
 | 
					  if (options.Get("postData", &body)) {
 | 
				
			||||||
 | 
					    params.post_data = body;
 | 
				
			||||||
 | 
					    params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  params.transition_type = ui::PAGE_TRANSITION_TYPED;
 | 
					  params.transition_type = ui::PAGE_TRANSITION_TYPED;
 | 
				
			||||||
  params.should_clear_history_list = true;
 | 
					  params.should_clear_history_list = true;
 | 
				
			||||||
  params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
 | 
					  params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,10 @@ namespace brightray {
 | 
				
			||||||
class InspectableWebContents;
 | 
					class InspectableWebContents;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace content {
 | 
				
			||||||
 | 
					class ResourceRequestBodyImpl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mate {
 | 
					namespace mate {
 | 
				
			||||||
class Arguments;
 | 
					class Arguments;
 | 
				
			||||||
class Dictionary;
 | 
					class Dictionary;
 | 
				
			||||||
| 
						 | 
					@ -176,10 +180,12 @@ class WebContents : public mate::TrackableObject<WebContents>,
 | 
				
			||||||
                                   bool allowed);
 | 
					                                   bool allowed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Create window with the given disposition.
 | 
					  // Create window with the given disposition.
 | 
				
			||||||
  void OnCreateWindow(const GURL& target_url,
 | 
					  void OnCreateWindow(
 | 
				
			||||||
 | 
					      const GURL& target_url,
 | 
				
			||||||
      const std::string& frame_name,
 | 
					      const std::string& frame_name,
 | 
				
			||||||
      WindowOpenDisposition disposition,
 | 
					      WindowOpenDisposition disposition,
 | 
				
			||||||
                      const std::vector<base::string16>& features);
 | 
					      const std::vector<base::string16>& features,
 | 
				
			||||||
 | 
					      const scoped_refptr<content::ResourceRequestBodyImpl>& body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Returns the web preferences of current WebContents.
 | 
					  // Returns the web preferences of current WebContents.
 | 
				
			||||||
  v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate);
 | 
					  v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@
 | 
				
			||||||
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
 | 
					#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
 | 
				
			||||||
#include "chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.h"
 | 
					#include "chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.h"
 | 
				
			||||||
#include "chrome/browser/speech/tts_message_filter.h"
 | 
					#include "chrome/browser/speech/tts_message_filter.h"
 | 
				
			||||||
 | 
					#include "content/common/resource_request_body_impl.h"
 | 
				
			||||||
#include "content/public/browser/browser_ppapi_host.h"
 | 
					#include "content/public/browser/browser_ppapi_host.h"
 | 
				
			||||||
#include "content/public/browser/client_certificate_delegate.h"
 | 
					#include "content/public/browser/client_certificate_delegate.h"
 | 
				
			||||||
#include "content/public/browser/geolocation_delegate.h"
 | 
					#include "content/public/browser/geolocation_delegate.h"
 | 
				
			||||||
| 
						 | 
					@ -319,7 +320,7 @@ bool AtomBrowserClient::CanCreateWindow(
 | 
				
			||||||
    WindowOpenDisposition disposition,
 | 
					    WindowOpenDisposition disposition,
 | 
				
			||||||
    const blink::WebWindowFeatures& features,
 | 
					    const blink::WebWindowFeatures& features,
 | 
				
			||||||
    const std::vector<base::string16>& additional_features,
 | 
					    const std::vector<base::string16>& additional_features,
 | 
				
			||||||
    const scoped_refptr<ResourceRequestBodyImpl>& body,
 | 
					    const scoped_refptr<content::ResourceRequestBodyImpl>& body,
 | 
				
			||||||
    bool user_gesture,
 | 
					    bool user_gesture,
 | 
				
			||||||
    bool opener_suppressed,
 | 
					    bool opener_suppressed,
 | 
				
			||||||
    content::ResourceContext* context,
 | 
					    content::ResourceContext* context,
 | 
				
			||||||
| 
						 | 
					@ -342,6 +343,7 @@ bool AtomBrowserClient::CanCreateWindow(
 | 
				
			||||||
                                    frame_name,
 | 
					                                    frame_name,
 | 
				
			||||||
                                    disposition,
 | 
					                                    disposition,
 | 
				
			||||||
                                    additional_features,
 | 
					                                    additional_features,
 | 
				
			||||||
 | 
					                                    body,
 | 
				
			||||||
                                    render_process_id,
 | 
					                                    render_process_id,
 | 
				
			||||||
                                    opener_render_frame_id));
 | 
					                                    opener_render_frame_id));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,8 +13,6 @@
 | 
				
			||||||
#include "brightray/browser/browser_client.h"
 | 
					#include "brightray/browser/browser_client.h"
 | 
				
			||||||
#include "content/public/browser/render_process_host_observer.h"
 | 
					#include "content/public/browser/render_process_host_observer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using content::ResourceRequestBodyImpl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace content {
 | 
					namespace content {
 | 
				
			||||||
class QuotaPermissionContext;
 | 
					class QuotaPermissionContext;
 | 
				
			||||||
class ClientCertificateDelegate;
 | 
					class ClientCertificateDelegate;
 | 
				
			||||||
| 
						 | 
					@ -81,7 +79,8 @@ class AtomBrowserClient : public brightray::BrowserClient,
 | 
				
			||||||
      net::SSLCertRequestInfo* cert_request_info,
 | 
					      net::SSLCertRequestInfo* cert_request_info,
 | 
				
			||||||
      std::unique_ptr<content::ClientCertificateDelegate> delegate) override;
 | 
					      std::unique_ptr<content::ClientCertificateDelegate> delegate) override;
 | 
				
			||||||
  void ResourceDispatcherHostCreated() override;
 | 
					  void ResourceDispatcherHostCreated() override;
 | 
				
			||||||
  bool CanCreateWindow(const GURL& opener_url,
 | 
					  bool CanCreateWindow(
 | 
				
			||||||
 | 
					      const GURL& opener_url,
 | 
				
			||||||
      const GURL& opener_top_level_frame_url,
 | 
					      const GURL& opener_top_level_frame_url,
 | 
				
			||||||
      const GURL& source_origin,
 | 
					      const GURL& source_origin,
 | 
				
			||||||
      WindowContainerType container_type,
 | 
					      WindowContainerType container_type,
 | 
				
			||||||
| 
						 | 
					@ -91,7 +90,7 @@ class AtomBrowserClient : public brightray::BrowserClient,
 | 
				
			||||||
      WindowOpenDisposition disposition,
 | 
					      WindowOpenDisposition disposition,
 | 
				
			||||||
      const blink::WebWindowFeatures& features,
 | 
					      const blink::WebWindowFeatures& features,
 | 
				
			||||||
      const std::vector<base::string16>& additional_features,
 | 
					      const std::vector<base::string16>& additional_features,
 | 
				
			||||||
                       const scoped_refptr<ResourceRequestBodyImpl>& body,
 | 
					      const scoped_refptr<content::ResourceRequestBodyImpl>& body,
 | 
				
			||||||
      bool user_gesture,
 | 
					      bool user_gesture,
 | 
				
			||||||
      bool opener_suppressed,
 | 
					      bool opener_suppressed,
 | 
				
			||||||
      content::ResourceContext* context,
 | 
					      content::ResourceContext* context,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,10 +14,14 @@
 | 
				
			||||||
#include "atom/common/native_mate_converters/gurl_converter.h"
 | 
					#include "atom/common/native_mate_converters/gurl_converter.h"
 | 
				
			||||||
#include "atom/common/native_mate_converters/string16_converter.h"
 | 
					#include "atom/common/native_mate_converters/string16_converter.h"
 | 
				
			||||||
#include "atom/common/native_mate_converters/ui_base_types_converter.h"
 | 
					#include "atom/common/native_mate_converters/ui_base_types_converter.h"
 | 
				
			||||||
 | 
					#include "atom/common/native_mate_converters/value_converter.h"
 | 
				
			||||||
 | 
					#include "content/common/resource_request_body_impl.h"
 | 
				
			||||||
#include "content/public/browser/web_contents.h"
 | 
					#include "content/public/browser/web_contents.h"
 | 
				
			||||||
#include "content/public/common/context_menu_params.h"
 | 
					#include "content/public/common/context_menu_params.h"
 | 
				
			||||||
#include "native_mate/dictionary.h"
 | 
					#include "native_mate/dictionary.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using content::ResourceRequestBodyImpl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ExecuteCommand(content::WebContents* web_contents,
 | 
					void ExecuteCommand(content::WebContents* web_contents,
 | 
				
			||||||
| 
						 | 
					@ -195,6 +199,102 @@ bool Converter<content::StopFindAction>::FromV8(
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					v8::Local<v8::Value>
 | 
				
			||||||
 | 
					Converter<scoped_refptr<ResourceRequestBodyImpl>>::ToV8(
 | 
				
			||||||
 | 
					    v8::Isolate* isolate,
 | 
				
			||||||
 | 
					    const scoped_refptr<ResourceRequestBodyImpl>& val) {
 | 
				
			||||||
 | 
					  if (!val)
 | 
				
			||||||
 | 
					    return v8::Null(isolate);
 | 
				
			||||||
 | 
					  std::unique_ptr<base::ListValue> list(new base::ListValue);
 | 
				
			||||||
 | 
					  for (const auto& element : *(val->elements())) {
 | 
				
			||||||
 | 
					    std::unique_ptr<base::DictionaryValue> post_data_dict(
 | 
				
			||||||
 | 
					        new base::DictionaryValue);
 | 
				
			||||||
 | 
					    auto type = element.type();
 | 
				
			||||||
 | 
					    if (type == ResourceRequestBodyImpl::Element::TYPE_BYTES) {
 | 
				
			||||||
 | 
					      std::unique_ptr<base::Value> bytes(
 | 
				
			||||||
 | 
					          base::BinaryValue::CreateWithCopiedBuffer(
 | 
				
			||||||
 | 
					              element.bytes(), static_cast<size_t>(element.length())));
 | 
				
			||||||
 | 
					      post_data_dict->SetString("type", "rawData");
 | 
				
			||||||
 | 
					      post_data_dict->Set("bytes", std::move(bytes));
 | 
				
			||||||
 | 
					    } else if (type == ResourceRequestBodyImpl::Element::TYPE_FILE) {
 | 
				
			||||||
 | 
					      post_data_dict->SetString("type", "file");
 | 
				
			||||||
 | 
					      post_data_dict->SetStringWithoutPathExpansion(
 | 
				
			||||||
 | 
					          "filePath", element.path().AsUTF8Unsafe());
 | 
				
			||||||
 | 
					      post_data_dict->SetInteger("offset", static_cast<int>(element.offset()));
 | 
				
			||||||
 | 
					      post_data_dict->SetInteger("length", static_cast<int>(element.length()));
 | 
				
			||||||
 | 
					      post_data_dict->SetDouble(
 | 
				
			||||||
 | 
					          "modificationTime", element.expected_modification_time().ToDoubleT());
 | 
				
			||||||
 | 
					    } else if (type == ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM) {
 | 
				
			||||||
 | 
					      post_data_dict->SetString("type", "fileSystem");
 | 
				
			||||||
 | 
					      post_data_dict->SetStringWithoutPathExpansion(
 | 
				
			||||||
 | 
					          "fileSystemURL", element.filesystem_url().spec());
 | 
				
			||||||
 | 
					      post_data_dict->SetInteger("offset", static_cast<int>(element.offset()));
 | 
				
			||||||
 | 
					      post_data_dict->SetInteger("length", static_cast<int>(element.length()));
 | 
				
			||||||
 | 
					      post_data_dict->SetDouble(
 | 
				
			||||||
 | 
					          "modificationTime", element.expected_modification_time().ToDoubleT());
 | 
				
			||||||
 | 
					    } else if (type == ResourceRequestBodyImpl::Element::TYPE_BLOB) {
 | 
				
			||||||
 | 
					      post_data_dict->SetString("type", "blob");
 | 
				
			||||||
 | 
					      post_data_dict->SetString("blobUUID", element.blob_uuid());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    list->Append(std::move(post_data_dict));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return ConvertToV8(isolate, *list);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static
 | 
				
			||||||
 | 
					bool Converter<scoped_refptr<ResourceRequestBodyImpl>>::FromV8(
 | 
				
			||||||
 | 
					    v8::Isolate* isolate,
 | 
				
			||||||
 | 
					    v8::Local<v8::Value> val,
 | 
				
			||||||
 | 
					    scoped_refptr<ResourceRequestBodyImpl>* out) {
 | 
				
			||||||
 | 
					  std::unique_ptr<base::ListValue> list(new base::ListValue);
 | 
				
			||||||
 | 
					  if (!ConvertFromV8(isolate, val, list.get()))
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  *out = new content::ResourceRequestBodyImpl();
 | 
				
			||||||
 | 
					  for (size_t i = 0; i < list->GetSize(); ++i) {
 | 
				
			||||||
 | 
					    base::DictionaryValue* dict = nullptr;
 | 
				
			||||||
 | 
					    std::string type;
 | 
				
			||||||
 | 
					    if (!list->GetDictionary(i, &dict))
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    dict->GetString("type", &type);
 | 
				
			||||||
 | 
					    if (type == "rawData") {
 | 
				
			||||||
 | 
					      base::BinaryValue* bytes = nullptr;
 | 
				
			||||||
 | 
					      dict->GetBinary("bytes", &bytes);
 | 
				
			||||||
 | 
					      (*out)->AppendBytes(bytes->GetBuffer(), bytes->GetSize());
 | 
				
			||||||
 | 
					    } else if (type == "file") {
 | 
				
			||||||
 | 
					      std::string file;
 | 
				
			||||||
 | 
					      int offset = 0, length = -1;
 | 
				
			||||||
 | 
					      double modification_time = 0.0;
 | 
				
			||||||
 | 
					      dict->GetStringWithoutPathExpansion("filePath", &file);
 | 
				
			||||||
 | 
					      dict->GetInteger("offset", &offset);
 | 
				
			||||||
 | 
					      dict->GetInteger("file", &length);
 | 
				
			||||||
 | 
					      dict->GetDouble("modificationTime", &modification_time);
 | 
				
			||||||
 | 
					      (*out)->AppendFileRange(base::FilePath::FromUTF8Unsafe(file),
 | 
				
			||||||
 | 
					                              static_cast<uint64_t>(offset),
 | 
				
			||||||
 | 
					                              static_cast<uint64_t>(length),
 | 
				
			||||||
 | 
					                              base::Time::FromDoubleT(modification_time));
 | 
				
			||||||
 | 
					    } else if (type == "fileSystem") {
 | 
				
			||||||
 | 
					      std::string file_system_url;
 | 
				
			||||||
 | 
					      int offset = 0, length = -1;
 | 
				
			||||||
 | 
					      double modification_time = 0.0;
 | 
				
			||||||
 | 
					      dict->GetStringWithoutPathExpansion("fileSystemURL", &file_system_url);
 | 
				
			||||||
 | 
					      dict->GetInteger("offset", &offset);
 | 
				
			||||||
 | 
					      dict->GetInteger("file", &length);
 | 
				
			||||||
 | 
					      dict->GetDouble("modificationTime", &modification_time);
 | 
				
			||||||
 | 
					      (*out)->AppendFileSystemFileRange(
 | 
				
			||||||
 | 
					          GURL(file_system_url),
 | 
				
			||||||
 | 
					          static_cast<uint64_t>(offset),
 | 
				
			||||||
 | 
					          static_cast<uint64_t>(length),
 | 
				
			||||||
 | 
					          base::Time::FromDoubleT(modification_time));
 | 
				
			||||||
 | 
					    } else if (type == "blob") {
 | 
				
			||||||
 | 
					      std::string uuid;
 | 
				
			||||||
 | 
					      dict->GetString("blobUUID", &uuid);
 | 
				
			||||||
 | 
					      (*out)->AppendBlob(uuid);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// static
 | 
					// static
 | 
				
			||||||
v8::Local<v8::Value> Converter<content::WebContents*>::ToV8(
 | 
					v8::Local<v8::Value> Converter<content::WebContents*>::ToV8(
 | 
				
			||||||
    v8::Isolate* isolate, content::WebContents* val) {
 | 
					    v8::Isolate* isolate, content::WebContents* val) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace content {
 | 
					namespace content {
 | 
				
			||||||
struct ContextMenuParams;
 | 
					struct ContextMenuParams;
 | 
				
			||||||
 | 
					class ResourceRequestBodyImpl;
 | 
				
			||||||
class WebContents;
 | 
					class WebContents;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,6 +48,15 @@ struct Converter<content::PermissionType> {
 | 
				
			||||||
                                   const content::PermissionType& val);
 | 
					                                   const content::PermissionType& val);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<>
 | 
				
			||||||
 | 
					struct Converter<scoped_refptr<content::ResourceRequestBodyImpl>> {
 | 
				
			||||||
 | 
					  static v8::Local<v8::Value> ToV8(
 | 
				
			||||||
 | 
					      v8::Isolate* isolate,
 | 
				
			||||||
 | 
					      const scoped_refptr<content::ResourceRequestBodyImpl>& val);
 | 
				
			||||||
 | 
					  static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
 | 
				
			||||||
 | 
					                     scoped_refptr<content::ResourceRequestBodyImpl>* out);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<>
 | 
					template<>
 | 
				
			||||||
struct Converter<content::StopFindAction> {
 | 
					struct Converter<content::StopFindAction> {
 | 
				
			||||||
  static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
 | 
					  static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -969,6 +969,7 @@ Same as `webContents.capturePage([rect, ]callback)`.
 | 
				
			||||||
  * `httpReferrer` String (optional) - A HTTP Referrer url.
 | 
					  * `httpReferrer` String (optional) - A HTTP Referrer url.
 | 
				
			||||||
  * `userAgent` String (optional) - A user agent originating the request.
 | 
					  * `userAgent` String (optional) - A user agent originating the request.
 | 
				
			||||||
  * `extraHeaders` String (optional) - Extra headers separated by "\n"
 | 
					  * `extraHeaders` String (optional) - Extra headers separated by "\n"
 | 
				
			||||||
 | 
					  * `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md) | [UploadFileSystem](structures/upload-file-system.md) | [UploadBlob](structures/upload-blob.md))[] (optional)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Same as `webContents.loadURL(url[, options])`.
 | 
					Same as `webContents.loadURL(url[, options])`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										4
									
								
								docs/api/structures/upload-blob.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								docs/api/structures/upload-blob.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					# Upload Blob Object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `type` String - `blob`.
 | 
				
			||||||
 | 
					* `blobUUID` String - UUID of blob data to upload.
 | 
				
			||||||
							
								
								
									
										9
									
								
								docs/api/structures/upload-file-system.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								docs/api/structures/upload-file-system.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					# Upload FileSystem Object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `type` String - `fileSystem`.
 | 
				
			||||||
 | 
					* `filsSystemURL` String - FileSystem url to read data for upload.
 | 
				
			||||||
 | 
					* `offset` Integer - Defaults to `0`.
 | 
				
			||||||
 | 
					* `length` Integer - Number of bytes to read from `offset`.
 | 
				
			||||||
 | 
					  Defaults to `0`.
 | 
				
			||||||
 | 
					* `modificationTime` Double - Last Modification time in
 | 
				
			||||||
 | 
					  number of seconds sine the UNIX epoch.
 | 
				
			||||||
							
								
								
									
										9
									
								
								docs/api/structures/upload-file.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								docs/api/structures/upload-file.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					# Upload File Object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `type` String - `file`.
 | 
				
			||||||
 | 
					* `filePath` String - Path of file to be uploaded.
 | 
				
			||||||
 | 
					* `offset` Integer - Defaults to `0`.
 | 
				
			||||||
 | 
					* `length` Integer - Number of bytes to read from `offset`.
 | 
				
			||||||
 | 
					  Defaults to `0`.
 | 
				
			||||||
 | 
					* `modificationTime` Double - Last Modification time in
 | 
				
			||||||
 | 
					  number of seconds sine the UNIX epoch.
 | 
				
			||||||
							
								
								
									
										4
									
								
								docs/api/structures/upload-raw-data.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								docs/api/structures/upload-raw-data.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					# Upload RawData Object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `type` String - `rawData`.
 | 
				
			||||||
 | 
					* `bytes` Buffer - Data to be uploaded.
 | 
				
			||||||
| 
						 | 
					@ -487,9 +487,10 @@ win.loadURL('http://github.com')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `url` URL
 | 
					* `url` URL
 | 
				
			||||||
* `options` Object (optional)
 | 
					* `options` Object (optional)
 | 
				
			||||||
  * `httpReferrer` String - A HTTP Referrer url.
 | 
					  * `httpReferrer` String (optional) - A HTTP Referrer url.
 | 
				
			||||||
  * `userAgent` String - A user agent originating the request.
 | 
					  * `userAgent` String (optional) - A user agent originating the request.
 | 
				
			||||||
  * `extraHeaders` String - Extra headers separated by "\n"
 | 
					  * `extraHeaders` String (optional) - Extra headers separated by "\n"
 | 
				
			||||||
 | 
					  * `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md) | [UploadFileSystem](structures/upload-file-system.md) | [UploadBlob](structures/upload-blob.md))[] (optional)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Loads the `url` in the window. The `url` must contain the protocol prefix,
 | 
					Loads the `url` in the window. The `url` must contain the protocol prefix,
 | 
				
			||||||
e.g. the `http://` or `file://`. If the load should bypass http cache then
 | 
					e.g. the `http://` or `file://`. If the load should bypass http cache then
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -262,9 +262,10 @@ webview.addEventListener('dom-ready', () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `url` URL
 | 
					* `url` URL
 | 
				
			||||||
* `options` Object (optional)
 | 
					* `options` Object (optional)
 | 
				
			||||||
  * `httpReferrer` String - A HTTP Referrer url.
 | 
					  * `httpReferrer` String (optional) - A HTTP Referrer url.
 | 
				
			||||||
  * `userAgent` String - A user agent originating the request.
 | 
					  * `userAgent` String (optional) - A user agent originating the request.
 | 
				
			||||||
  * `extraHeaders` String - Extra headers separated by "\n"
 | 
					  * `extraHeaders` String (optional) - Extra headers separated by "\n"
 | 
				
			||||||
 | 
					  * `postData` ([UploadRawData](structures/upload-raw-data.md) | [UploadFile](structures/upload-file.md) | [UploadFileSystem](structures/upload-file-system.md) | [UploadBlob](structures/upload-blob.md))[] (optional)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Loads the `url` in the webview, the `url` must contain the protocol prefix,
 | 
					Loads the `url` in the webview, the `url` must contain the protocol prefix,
 | 
				
			||||||
e.g. the `http://` or `file://`.
 | 
					e.g. the `http://` or `file://`.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,13 +18,17 @@ BrowserWindow.prototype._init = function () {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Make new windows requested by links behave like "window.open"
 | 
					  // Make new windows requested by links behave like "window.open"
 | 
				
			||||||
  this.webContents.on('-new-window', (event, url, frameName, disposition, additionalFeatures) => {
 | 
					  this.webContents.on('-new-window', (event, url, frameName,
 | 
				
			||||||
 | 
					                                      disposition, additionalFeatures,
 | 
				
			||||||
 | 
					                                      postData) => {
 | 
				
			||||||
    const options = {
 | 
					    const options = {
 | 
				
			||||||
      show: true,
 | 
					      show: true,
 | 
				
			||||||
      width: 800,
 | 
					      width: 800,
 | 
				
			||||||
      height: 600
 | 
					      height: 600
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    ipcMain.emit('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, disposition, options, additionalFeatures)
 | 
					    ipcMain.emit('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN',
 | 
				
			||||||
 | 
					                 event, url, frameName, disposition,
 | 
				
			||||||
 | 
					                 options, additionalFeatures, postData)
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  this.webContents.on('-web-contents-created', (event, webContents, url,
 | 
					  this.webContents.on('-web-contents-created', (event, webContents, url,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,7 +84,7 @@ const setupGuest = function (embedder, frameName, guest, options) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create a new guest created by |embedder| with |options|.
 | 
					// Create a new guest created by |embedder| with |options|.
 | 
				
			||||||
const createGuest = function (embedder, url, frameName, options) {
 | 
					const createGuest = function (embedder, url, frameName, options, postData) {
 | 
				
			||||||
  let guest = frameToGuest[frameName]
 | 
					  let guest = frameToGuest[frameName]
 | 
				
			||||||
  if (frameName && (guest != null)) {
 | 
					  if (frameName && (guest != null)) {
 | 
				
			||||||
    guest.loadURL(url)
 | 
					    guest.loadURL(url)
 | 
				
			||||||
| 
						 | 
					@ -119,7 +119,19 @@ const createGuest = function (embedder, url, frameName, options) {
 | 
				
			||||||
    //
 | 
					    //
 | 
				
			||||||
    // The above code would not work if a navigation to "about:blank" is done
 | 
					    // The above code would not work if a navigation to "about:blank" is done
 | 
				
			||||||
    // here, since the window would be cleared of all changes in the next tick.
 | 
					    // here, since the window would be cleared of all changes in the next tick.
 | 
				
			||||||
    guest.loadURL(url)
 | 
					    const loadOptions = {}
 | 
				
			||||||
 | 
					    if (postData != null) {
 | 
				
			||||||
 | 
					      loadOptions.postData = postData
 | 
				
			||||||
 | 
					      loadOptions.extraHeaders = 'content-type: application/x-www-form-urlencoded'
 | 
				
			||||||
 | 
					      if (postData.length > 0) {
 | 
				
			||||||
 | 
					        const postDataFront = postData[0].bytes.toString()
 | 
				
			||||||
 | 
					        const boundary = /^--.*[^-\r\n]/.exec(postDataFront)
 | 
				
			||||||
 | 
					        if (boundary != null) {
 | 
				
			||||||
 | 
					          loadOptions.extraHeaders = `content-type: multipart/form-data; boundary=${boundary[0].substr(2)}`
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    guest.loadURL(url, loadOptions)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return setupGuest(embedder, frameName, guest, options)
 | 
					  return setupGuest(embedder, frameName, guest, options)
 | 
				
			||||||
| 
						 | 
					@ -140,7 +152,9 @@ const getGuestWindow = function (guestId) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Routed window.open messages.
 | 
					// Routed window.open messages.
 | 
				
			||||||
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, frameName, disposition, options, additionalFeatures) {
 | 
					ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, frameName,
 | 
				
			||||||
 | 
					                                                                  disposition, options,
 | 
				
			||||||
 | 
					                                                                  additionalFeatures, postData) {
 | 
				
			||||||
  options = mergeBrowserWindowOptions(event.sender, options)
 | 
					  options = mergeBrowserWindowOptions(event.sender, options)
 | 
				
			||||||
  event.sender.emit('new-window', event, url, frameName, disposition, options, additionalFeatures)
 | 
					  event.sender.emit('new-window', event, url, frameName, disposition, options, additionalFeatures)
 | 
				
			||||||
  const newGuest = event.newGuest
 | 
					  const newGuest = event.newGuest
 | 
				
			||||||
| 
						 | 
					@ -151,7 +165,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, fr
 | 
				
			||||||
      event.returnValue = null
 | 
					      event.returnValue = null
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    event.returnValue = createGuest(event.sender, url, frameName, options)
 | 
					    event.returnValue = createGuest(event.sender, url, frameName, options, postData)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,28 +4,59 @@ const assert = require('assert')
 | 
				
			||||||
const fs = require('fs')
 | 
					const fs = require('fs')
 | 
				
			||||||
const path = require('path')
 | 
					const path = require('path')
 | 
				
			||||||
const os = require('os')
 | 
					const os = require('os')
 | 
				
			||||||
 | 
					const qs = require('querystring')
 | 
				
			||||||
const http = require('http')
 | 
					const http = require('http')
 | 
				
			||||||
const {closeWindow} = require('./window-helpers')
 | 
					const {closeWindow} = require('./window-helpers')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const remote = require('electron').remote
 | 
					const {ipcRenderer, remote, screen} = require('electron')
 | 
				
			||||||
const screen = require('electron').screen
 | 
					const {app, ipcMain, BrowserWindow, protocol} = remote
 | 
				
			||||||
 | 
					 | 
				
			||||||
const app = remote.require('electron').app
 | 
					 | 
				
			||||||
const ipcMain = remote.require('electron').ipcMain
 | 
					 | 
				
			||||||
const ipcRenderer = require('electron').ipcRenderer
 | 
					 | 
				
			||||||
const BrowserWindow = remote.require('electron').BrowserWindow
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const isCI = remote.getGlobal('isCi')
 | 
					const isCI = remote.getGlobal('isCi')
 | 
				
			||||||
const {protocol} = remote
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('browser-window module', function () {
 | 
					describe('browser-window module', function () {
 | 
				
			||||||
  var fixtures = path.resolve(__dirname, 'fixtures')
 | 
					  var fixtures = path.resolve(__dirname, 'fixtures')
 | 
				
			||||||
  var w = null
 | 
					  var w = null
 | 
				
			||||||
  var server
 | 
					  var server, postData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  before(function (done) {
 | 
					  before(function (done) {
 | 
				
			||||||
 | 
					    const filePath = path.join(fixtures, 'pages', 'a.html')
 | 
				
			||||||
 | 
					    const fileStats = fs.statSync(filePath)
 | 
				
			||||||
 | 
					    postData = [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        type: 'rawData',
 | 
				
			||||||
 | 
					        bytes: new Buffer('username=test&file=')
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        type: 'file',
 | 
				
			||||||
 | 
					        filePath: filePath,
 | 
				
			||||||
 | 
					        offset: 0,
 | 
				
			||||||
 | 
					        length: fileStats.size,
 | 
				
			||||||
 | 
					        modificationTime: fileStats.mtime.getTime() / 1000
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
    server = http.createServer(function (req, res) {
 | 
					    server = http.createServer(function (req, res) {
 | 
				
			||||||
      function respond () { res.end('') }
 | 
					      function respond () {
 | 
				
			||||||
 | 
					        if (req.method === 'POST') {
 | 
				
			||||||
 | 
					          let body = ''
 | 
				
			||||||
 | 
					          req.on('data', (data) => {
 | 
				
			||||||
 | 
					            if (data) {
 | 
				
			||||||
 | 
					              body += data
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          req.on('end', () => {
 | 
				
			||||||
 | 
					            let parsedData = qs.parse(body)
 | 
				
			||||||
 | 
					            fs.readFile(filePath, (err, data) => {
 | 
				
			||||||
 | 
					              if (err) return
 | 
				
			||||||
 | 
					              if (parsedData.username === 'test' &&
 | 
				
			||||||
 | 
					                  parsedData.file === data.toString()) {
 | 
				
			||||||
 | 
					                res.end()
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          res.end()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      setTimeout(respond, req.url.includes('slow') ? 200 : 0)
 | 
					      setTimeout(respond, req.url.includes('slow') ? 200 : 0)
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    server.listen(0, '127.0.0.1', function () {
 | 
					    server.listen(0, '127.0.0.1', function () {
 | 
				
			||||||
| 
						 | 
					@ -187,6 +218,54 @@ describe('browser-window module', function () {
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      w.loadURL('http://127.0.0.1:11111')
 | 
					      w.loadURL('http://127.0.0.1:11111')
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe('POST navigations', function () {
 | 
				
			||||||
 | 
					      afterEach(() => {
 | 
				
			||||||
 | 
					        w.webContents.session.webRequest.onBeforeSendHeaders(null)
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it('supports specifying POST data', function (done) {
 | 
				
			||||||
 | 
					        w.webContents.on('did-finish-load', () => done())
 | 
				
			||||||
 | 
					        w.loadURL(server.url, {postData: postData})
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it('sets the content type header on URL encoded forms', function (done) {
 | 
				
			||||||
 | 
					        w.webContents.on('did-finish-load', () => {
 | 
				
			||||||
 | 
					          w.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => {
 | 
				
			||||||
 | 
					            assert.equal(details.requestHeaders['content-type'], 'application/x-www-form-urlencoded')
 | 
				
			||||||
 | 
					            done()
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          w.webContents.executeJavaScript(`
 | 
				
			||||||
 | 
					            form = document.createElement('form')
 | 
				
			||||||
 | 
					            form.method = 'POST'
 | 
				
			||||||
 | 
					            form.target = '_blank'
 | 
				
			||||||
 | 
					            form.submit()
 | 
				
			||||||
 | 
					          `)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        w.loadURL(server.url)
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it('sets the content type header on multi part forms', function (done) {
 | 
				
			||||||
 | 
					        w.webContents.on('did-finish-load', () => {
 | 
				
			||||||
 | 
					          w.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => {
 | 
				
			||||||
 | 
					            assert(details.requestHeaders['content-type'].startsWith('multipart/form-data; boundary=----WebKitFormBoundary'))
 | 
				
			||||||
 | 
					            done()
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          w.webContents.executeJavaScript(`
 | 
				
			||||||
 | 
					            form = document.createElement('form')
 | 
				
			||||||
 | 
					            form.method = 'POST'
 | 
				
			||||||
 | 
					            form.target = '_blank'
 | 
				
			||||||
 | 
					            form.enctype = 'multipart/form-data'
 | 
				
			||||||
 | 
					            file = document.createElement('input')
 | 
				
			||||||
 | 
					            file.type = 'file'
 | 
				
			||||||
 | 
					            file.name = 'file'
 | 
				
			||||||
 | 
					            form.appendChild(file)
 | 
				
			||||||
 | 
					            form.submit()
 | 
				
			||||||
 | 
					          `)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        w.loadURL(server.url)
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe('BrowserWindow.show()', function () {
 | 
					  describe('BrowserWindow.show()', function () {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue