Merge branch 'master' into native-window-open
This commit is contained in:
commit
1d73e84a29
59 changed files with 989 additions and 241 deletions
|
@ -655,6 +655,14 @@ void App::OnGpuProcessCrashed(base::TerminationStatus status) {
|
|||
status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
|
||||
}
|
||||
|
||||
base::FilePath App::GetAppPath() const {
|
||||
return app_path_;
|
||||
}
|
||||
|
||||
void App::SetAppPath(const base::FilePath& app_path) {
|
||||
app_path_ = app_path;
|
||||
}
|
||||
|
||||
base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) {
|
||||
bool succeed = false;
|
||||
base::FilePath path;
|
||||
|
@ -959,6 +967,8 @@ void App::BuildPrototype(
|
|||
.SetMethod("isUnityRunning",
|
||||
base::Bind(&Browser::IsUnityRunning, browser))
|
||||
#endif
|
||||
.SetMethod("setAppPath", &App::SetAppPath)
|
||||
.SetMethod("getAppPath", &App::GetAppPath)
|
||||
.SetMethod("setPath", &App::SetPath)
|
||||
.SetMethod("getPath", &App::GetPath)
|
||||
.SetMethod("setDesktopName", &App::SetDesktopName)
|
||||
|
|
|
@ -70,6 +70,8 @@ class App : public AtomBrowserClient::Delegate,
|
|||
std::unique_ptr<CertificateManagerModel> model);
|
||||
#endif
|
||||
|
||||
base::FilePath GetAppPath() const;
|
||||
|
||||
protected:
|
||||
explicit App(v8::Isolate* isolate);
|
||||
~App() override;
|
||||
|
@ -115,6 +117,8 @@ class App : public AtomBrowserClient::Delegate,
|
|||
void OnGpuProcessCrashed(base::TerminationStatus status) override;
|
||||
|
||||
private:
|
||||
void SetAppPath(const base::FilePath& app_path);
|
||||
|
||||
// Get/Set the pre-defined path in PathService.
|
||||
base::FilePath GetPath(mate::Arguments* args, const std::string& name);
|
||||
void SetPath(mate::Arguments* args,
|
||||
|
@ -154,6 +158,8 @@ class App : public AtomBrowserClient::Delegate,
|
|||
// Tracks tasks requesting file icons.
|
||||
base::CancelableTaskTracker cancelable_task_tracker_;
|
||||
|
||||
base::FilePath app_path_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(App);
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "atom/common/api/event_emitter_caller.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/time/time.h"
|
||||
|
@ -47,7 +48,9 @@ void AutoUpdater::OnError(const std::string& message) {
|
|||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
|
||||
EmitCustomEvent(
|
||||
mate::EmitEvent(
|
||||
isolate(),
|
||||
GetWrapper(),
|
||||
"error",
|
||||
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
|
||||
// Message is also emitted to keep compatibility with old code.
|
||||
|
|
|
@ -179,6 +179,13 @@ void OnSetCookie(const Cookies::SetCallback& callback, bool success) {
|
|||
base::Bind(callback, success ? Cookies::SUCCESS : Cookies::FAILED));
|
||||
}
|
||||
|
||||
// Flushes cookie store in IO thread.
|
||||
void FlushCookieStoreOnIOThread(
|
||||
scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
const base::Closure& callback) {
|
||||
GetCookieStore(getter)->FlushStore(base::Bind(RunCallbackInUI, callback));
|
||||
}
|
||||
|
||||
// Sets cookie with |details| in IO thread.
|
||||
void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
std::unique_ptr<base::DictionaryValue> details,
|
||||
|
@ -265,6 +272,13 @@ void Cookies::Set(const base::DictionaryValue& details,
|
|||
base::Bind(SetCookieOnIO, getter, Passed(&copied), callback));
|
||||
}
|
||||
|
||||
void Cookies::FlushStore(const base::Closure& callback) {
|
||||
auto getter = make_scoped_refptr(request_context_getter_);
|
||||
content::BrowserThread::PostTask(
|
||||
BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(FlushCookieStoreOnIOThread, getter, callback));
|
||||
}
|
||||
|
||||
void Cookies::OnCookieChanged(const net::CanonicalCookie& cookie,
|
||||
bool removed,
|
||||
net::CookieStore::ChangeCause cause) {
|
||||
|
@ -286,7 +300,8 @@ void Cookies::BuildPrototype(v8::Isolate* isolate,
|
|||
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||
.SetMethod("get", &Cookies::Get)
|
||||
.SetMethod("remove", &Cookies::Remove)
|
||||
.SetMethod("set", &Cookies::Set);
|
||||
.SetMethod("set", &Cookies::Set)
|
||||
.SetMethod("flushStore", &Cookies::FlushStore);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -53,6 +53,7 @@ class Cookies : public mate::TrackableObject<Cookies>,
|
|||
void Remove(const GURL& url, const std::string& name,
|
||||
const base::Closure& callback);
|
||||
void Set(const base::DictionaryValue& details, const SetCallback& callback);
|
||||
void FlushStore(const base::Closure& callback);
|
||||
|
||||
// AtomCookieDelegate::Observer:
|
||||
void OnCookieChanged(const net::CanonicalCookie& cookie,
|
||||
|
|
|
@ -191,6 +191,10 @@ void Window::OnWindowClosed() {
|
|||
FROM_HERE, GetDestroyClosure());
|
||||
}
|
||||
|
||||
void Window::OnWindowEndSession() {
|
||||
Emit("session-end");
|
||||
}
|
||||
|
||||
void Window::OnWindowBlur() {
|
||||
Emit("blur");
|
||||
}
|
||||
|
@ -263,6 +267,14 @@ void Window::OnWindowSwipe(const std::string& direction) {
|
|||
Emit("swipe", direction);
|
||||
}
|
||||
|
||||
void Window::OnWindowSheetBegin() {
|
||||
Emit("sheet-begin");
|
||||
}
|
||||
|
||||
void Window::OnWindowSheetEnd() {
|
||||
Emit("sheet-end");
|
||||
}
|
||||
|
||||
void Window::OnWindowEnterHtmlFullScreen() {
|
||||
Emit("enter-html-full-screen");
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ class Window : public mate::TrackableObject<Window>,
|
|||
void WillCloseWindow(bool* prevent_default) override;
|
||||
void WillDestroyNativeObject() override;
|
||||
void OnWindowClosed() override;
|
||||
void OnWindowEndSession() override;
|
||||
void OnWindowBlur() override;
|
||||
void OnWindowFocus() override;
|
||||
void OnWindowShow() override;
|
||||
|
@ -79,6 +80,8 @@ class Window : public mate::TrackableObject<Window>,
|
|||
void OnWindowScrollTouchEnd() override;
|
||||
void OnWindowScrollTouchEdge() override;
|
||||
void OnWindowSwipe(const std::string& direction) override;
|
||||
void OnWindowSheetBegin() override;
|
||||
void OnWindowSheetEnd() override;
|
||||
void OnWindowEnterFullScreen() override;
|
||||
void OnWindowLeaveFullScreen() override;
|
||||
void OnWindowEnterHtmlFullScreen() override;
|
||||
|
|
|
@ -261,6 +261,11 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
|||
}
|
||||
#endif
|
||||
|
||||
if (delegate_) {
|
||||
auto app_path = static_cast<api::App*>(delegate_)->GetAppPath();
|
||||
command_line->AppendSwitchPath(switches::kAppPath, app_path);
|
||||
}
|
||||
|
||||
content::WebContents* web_contents = GetWebContentsFromProcessID(process_id);
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
|
|
@ -474,6 +474,11 @@ void NativeWindow::NotifyWindowClosed() {
|
|||
observer.OnWindowClosed();
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowEndSession() {
|
||||
for (NativeWindowObserver& observer : observers_)
|
||||
observer.OnWindowEndSession();
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowBlur() {
|
||||
for (NativeWindowObserver& observer : observers_)
|
||||
observer.OnWindowBlur();
|
||||
|
@ -554,6 +559,16 @@ void NativeWindow::NotifyWindowSwipe(const std::string& direction) {
|
|||
observer.OnWindowSwipe(direction);
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowSheetBegin() {
|
||||
for (NativeWindowObserver& observer : observers_)
|
||||
observer.OnWindowSheetBegin();
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowSheetEnd() {
|
||||
for (NativeWindowObserver& observer : observers_)
|
||||
observer.OnWindowSheetEnd();
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowLeaveFullScreen() {
|
||||
for (NativeWindowObserver& observer : observers_)
|
||||
observer.OnWindowLeaveFullScreen();
|
||||
|
|
|
@ -218,6 +218,7 @@ class NativeWindow : public base::SupportsUserData,
|
|||
// Public API used by platform-dependent delegates and observers to send UI
|
||||
// related notifications.
|
||||
void NotifyWindowClosed();
|
||||
void NotifyWindowEndSession();
|
||||
void NotifyWindowBlur();
|
||||
void NotifyWindowFocus();
|
||||
void NotifyWindowShow();
|
||||
|
@ -233,6 +234,8 @@ class NativeWindow : public base::SupportsUserData,
|
|||
void NotifyWindowScrollTouchEnd();
|
||||
void NotifyWindowScrollTouchEdge();
|
||||
void NotifyWindowSwipe(const std::string& direction);
|
||||
void NotifyWindowSheetBegin();
|
||||
void NotifyWindowSheetEnd();
|
||||
void NotifyWindowEnterFullScreen();
|
||||
void NotifyWindowLeaveFullScreen();
|
||||
void NotifyWindowEnterHtmlFullScreen();
|
||||
|
|
|
@ -313,6 +313,14 @@ bool ScopedDisableResize::disable_resize_ = false;
|
|||
return rect;
|
||||
}
|
||||
|
||||
- (void)windowWillBeginSheet:(NSNotification *)notification {
|
||||
shell_->NotifyWindowSheetBegin();
|
||||
}
|
||||
|
||||
- (void)windowDidEndSheet:(NSNotification *)notification {
|
||||
shell_->NotifyWindowSheetEnd();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface AtomPreviewItem : NSObject <QLPreviewItem>
|
||||
|
|
|
@ -40,6 +40,9 @@ class NativeWindowObserver {
|
|||
// Called when the window is closed.
|
||||
virtual void OnWindowClosed() {}
|
||||
|
||||
// Called when Windows sends WM_ENDSESSION message
|
||||
virtual void OnWindowEndSession() {}
|
||||
|
||||
// Called when window loses focus.
|
||||
virtual void OnWindowBlur() {}
|
||||
|
||||
|
@ -67,6 +70,8 @@ class NativeWindowObserver {
|
|||
virtual void OnWindowScrollTouchEnd() {}
|
||||
virtual void OnWindowScrollTouchEdge() {}
|
||||
virtual void OnWindowSwipe(const std::string& direction) {}
|
||||
virtual void OnWindowSheetBegin() {}
|
||||
virtual void OnWindowSheetEnd() {}
|
||||
virtual void OnWindowEnterFullScreen() {}
|
||||
virtual void OnWindowLeaveFullScreen() {}
|
||||
virtual void OnWindowEnterHtmlFullScreen() {}
|
||||
|
|
|
@ -147,6 +147,11 @@ bool NativeWindowViews::PreHandleMSG(
|
|||
}
|
||||
return false;
|
||||
}
|
||||
case WM_ENDSESSION: {
|
||||
if (w_param) {
|
||||
NotifyWindowEndSession();
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<key>CFBundleIconFile</key>
|
||||
<string>electron.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.6.6</string>
|
||||
<string>1.6.7</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.6.6</string>
|
||||
<string>1.6.7</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
|
|
@ -56,8 +56,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,6,6,0
|
||||
PRODUCTVERSION 1,6,6,0
|
||||
FILEVERSION 1,6,7,0
|
||||
PRODUCTVERSION 1,6,7,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -74,12 +74,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "1.6.6"
|
||||
VALUE "FileVersion", "1.6.7"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "1.6.6"
|
||||
VALUE "ProductVersion", "1.6.7"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -310,6 +310,16 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item";
|
|||
gfx::Image image;
|
||||
if (settings.Get("icon", &image)) {
|
||||
button.image = image.AsNSImage();
|
||||
|
||||
std::string iconPosition;
|
||||
settings.Get("iconPosition", &iconPosition);
|
||||
if (iconPosition == "left") {
|
||||
button.imagePosition = NSImageLeft;
|
||||
} else if (iconPosition == "right") {
|
||||
button.imagePosition = NSImageRight;
|
||||
} else {
|
||||
button.imagePosition = NSImageOverlaps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#define ATOM_MAJOR_VERSION 1
|
||||
#define ATOM_MINOR_VERSION 6
|
||||
#define ATOM_PATCH_VERSION 6
|
||||
#define ATOM_PATCH_VERSION 7
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
|
|
@ -159,6 +159,9 @@ const char kSecureSchemes[] = "secure-schemes";
|
|||
// The browser process app model ID
|
||||
const char kAppUserModelId[] = "app-user-model-id";
|
||||
|
||||
// The application path
|
||||
const char kAppPath[] = "app-path";
|
||||
|
||||
// The command line switch versions of the options.
|
||||
const char kBackgroundColor[] = "background-color";
|
||||
const char kPreloadScript[] = "preload";
|
||||
|
|
|
@ -81,6 +81,7 @@ extern const char kStandardSchemes[];
|
|||
extern const char kRegisterServiceWorkerSchemes[];
|
||||
extern const char kSecureSchemes[];
|
||||
extern const char kAppUserModelId[];
|
||||
extern const char kAppPath[];
|
||||
|
||||
extern const char kBackgroundColor[];
|
||||
extern const char kPreloadScript[];
|
||||
|
|
File diff suppressed because one or more lines are too long
45
default_app/renderer.js
Normal file
45
default_app/renderer.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
const {remote, shell} = require('electron')
|
||||
const {execFile} = require('child_process')
|
||||
|
||||
const {execPath} = remote.process
|
||||
|
||||
document.onclick = function (e) {
|
||||
e.preventDefault()
|
||||
if (e.target.tagName === 'A') {
|
||||
shell.openExternal(e.target.href)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
document.ondragover = document.ondrop = function (e) {
|
||||
e.preventDefault()
|
||||
return false
|
||||
}
|
||||
|
||||
const holder = document.getElementById('holder')
|
||||
holder.ondragover = function () {
|
||||
this.className = 'hover'
|
||||
return false
|
||||
}
|
||||
|
||||
holder.ondragleave = holder.ondragend = function () {
|
||||
this.className = ''
|
||||
return false
|
||||
}
|
||||
|
||||
holder.ondrop = function (e) {
|
||||
this.className = ''
|
||||
e.preventDefault()
|
||||
|
||||
const file = e.dataTransfer.files[0]
|
||||
execFile(execPath, [file.path], {
|
||||
detached: true, stdio: 'ignore'
|
||||
}).unref()
|
||||
return false
|
||||
}
|
||||
|
||||
const version = process.versions.electron
|
||||
document.querySelector('.header-version').innerText = version
|
||||
document.querySelector('.command-example').innerText = `${execPath} path-to-your-app`
|
||||
document.querySelector('.quick-start-link').href = `https://github.com/electron/electron/blob/v${version}/docs/tutorial/quick-start.md`
|
||||
document.querySelector('.docs-link').href = `https://github.com/electron/electron/tree/v${version}/docs#readme`
|
|
@ -1,6 +1,6 @@
|
|||
# protocol
|
||||
|
||||
> 커스텀 프로토콜을 등록하거나 이미 존재하능 프로토콜의 요청의 동작을 변경합니다.
|
||||
> 커스텀 프로토콜을 등록하거나 이미 존재하는 프로토콜의 요청의 동작을 변경합니다.
|
||||
|
||||
프로세스: [메인](../tutorial/quick-start.md#main-process)
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ Bir problem(issue) bildirmeden önce sıkça sorulan sorulara göz atın:
|
|||
|
||||
## Eğitimler
|
||||
|
||||
* [Quick Start](https://github.com/electron/electron/tree/master/docs/tutorial/quick-start.md)
|
||||
* [Hızlı Başlangıç](tutorial/quick-start.md)
|
||||
* [Desktop Environment Integration](https://github.com/electron/electron/tree/master/docs/tutorial/desktop-environment-integration.md)
|
||||
* [Online/Offline Event Detection](https://github.com/electron/electron/tree/master/docs/tutorial/online-offline-events.md)
|
||||
|
||||
|
|
252
docs-translations/tr-TR/tutorial/quick-start.md
Normal file
252
docs-translations/tr-TR/tutorial/quick-start.md
Normal file
|
@ -0,0 +1,252 @@
|
|||
# Hızlı Başlangıç
|
||||
|
||||
Electron, zengin native(işletim sistemi) API runtime sağlayarak, saf Javascript
|
||||
ile masaüstü uygulamalar geliştirmenize yarar. Electron'u Node.js in, web serverları
|
||||
yerine masaüstü uygulamalara odaklanmış bir variyasyonu olarak kabul edebilirsiniz.
|
||||
|
||||
Bu Electronun, grafik kullanıcı arayüzüne bir JavaScript bağlantısı olduğu
|
||||
anlamına gelmez. Aksine, Electron web sayfalarını GUI'si olarak kullanır,
|
||||
yani onu Javascript tarafından kontrol edilen bir minimal Chromium tarayıcısı
|
||||
olarak görebilirsiniz.
|
||||
|
||||
### Ana İşlem
|
||||
|
||||
Electron da, `package.json` nun `main` skriptini cağıran işlem _the main process__ dir.
|
||||
Ana işlemde çalışan bu script, GUI'yi web sayfalarını oluşturarak gösterebilir.
|
||||
|
||||
### Render İşlemi
|
||||
|
||||
Electron, web sayfalarını görüntülemek için Chromium kullandığından,
|
||||
aynı zamanda Chromiumun multi-işlem mimarisinide kullanmaktadır.
|
||||
Electron da calıştırılan her web sayfası, __the renderer process__
|
||||
adı altında kendi işlemlerini çalıştırırlar.
|
||||
|
||||
Normal tarayıcılarda, web sayfaları genellikle korumalı bir ortamda çalışır ve
|
||||
yerel kaynaklara erişmesine izin verilmez. Bununla birlikte, elektron kullanıcıları,
|
||||
alt düzey işletim sistemi etkileşimlerine izin veren web sayfalarında
|
||||
Node.js API'lerini kullanma imkanina sahiplerdir.
|
||||
|
||||
### Ana işlem ile render işlemi arasındaki farklar
|
||||
|
||||
Ana işlem, `BrowserWindow` örneklerini oluşturarak, web sayfalarını hazır
|
||||
hale getirir. Her bir `BrowserWindow` örneği web sayfasını kendi render
|
||||
işleminde çalıştırır. Eger bir `BrowserWindow` örneği ortadan kaldırıldıysa,
|
||||
bununla bağlantılı olan render işlemide aynı şekilde sonlandırılır.
|
||||
|
||||
Ana işlem tüm web sayfaları ve onların ilgili olduğu render işlemlerini yönetir.
|
||||
Her bir render işlemi izole edilmiş ve sadece kendisinde çalışan web sayfasıyla ilgilenir.
|
||||
|
||||
Native GUI ile çalışan API ları web sayfalarında çalıştırmaya izin verilmemektedir,
|
||||
çünkü native GUI kaynaklarının web sayfalarında yönetimi çok tehlikeli ve
|
||||
kaynakların sızdırılması gayet kolaydır. Eğer GUI operasyonlarını bir web sayfasinda
|
||||
gerçekleştirmek istiyorsanız, web sayfasının render işlemi, ana işlem ile, bu tür
|
||||
işlemleri gerçekleştirilmesini talep etmek için kommunikasyon halinde olmalı.
|
||||
|
||||
Electron da ana işlem ve render işlemi arasında birden fazla kommunikasyon yolu vardır.
|
||||
[`ipcRenderer`](../api/ipc-renderer.md) gibi ve mesaj gönderimi icin
|
||||
[`ipcMain`](../api/ipc-main.md) modülleri, RPC tarzında kommunikasyon
|
||||
için ise [remote](../api/remote.md) modülü barındırmakta.
|
||||
Ayrıca SSS başlıkları [how to share data between web pages][share-data] adresinde bulunabilir.
|
||||
|
||||
## İlk Electron uygulamanızı yazın
|
||||
|
||||
Electron uygulaması genellikle aşağıdaki gibi yapılandırılmıştır:
|
||||
|
||||
```text
|
||||
your-app/
|
||||
├── package.json
|
||||
├── main.js
|
||||
└── index.html
|
||||
```
|
||||
|
||||
`package.json` dosyasının formatı tamamen Node modüllerine benzer veya aynıdır ve
|
||||
`main` şeklinde adlandırılmış script uygulamanızı başlatan komut dosyasıdır,
|
||||
bu komut dosyası daha sonra main process'i çalıştıracak dosyadır.
|
||||
`package.json` dosyasınızın bir örneği aşağıdaki gibi olabilir:
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"name" : "your-app",
|
||||
"version" : "0.1.0",
|
||||
"main" : "main.js"
|
||||
}
|
||||
```
|
||||
|
||||
__Note__: Eğer `package.json` dosyasında `main` kısmı bulunmuyorsa, Electron standart olarak
|
||||
`index.js` dosyasını cağıracaktır.
|
||||
|
||||
`main.js` dosyası pencereleri oluşturur, sistem durumlarını handle eder, tipik bir
|
||||
örnek asağıdaki gibidir:
|
||||
|
||||
```javascript
|
||||
const {app, BrowserWindow} = require('electron')
|
||||
const path = require('path')
|
||||
const url = require('url')
|
||||
|
||||
// Pencere objesini daima global referans olarak tanımla, aksi takdirde,
|
||||
// eğer JavaScript objesi gereksiz veriler toplayacağı için, pencere
|
||||
// otomatik olarak kapanacaktır.
|
||||
|
||||
let win
|
||||
|
||||
function createWindow () {
|
||||
// Tarayıcı pencerelerini oluşturur.
|
||||
win = new BrowserWindow({width: 800, height: 600})
|
||||
|
||||
// ve uygulamanın index.html sayfasını yükler.
|
||||
win.loadURL(url.format({
|
||||
pathname: path.join(__dirname, 'index.html'),
|
||||
protocol: 'file:',
|
||||
slashes: true
|
||||
}))
|
||||
|
||||
// DevTools her uygulama başlatıldığında açılır.
|
||||
|
||||
win.webContents.openDevTools()
|
||||
|
||||
// Pencere kapandıktan sonra çağrılacaktır.
|
||||
win.on('closed', () => {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
win = null
|
||||
})
|
||||
}
|
||||
|
||||
// Bu metod Electronun başlatılması tamamlandıktan sonra
|
||||
// çagrılacak ve yeni tarayıcı pencereleri açmaya hazır hale gelecektir.
|
||||
// Bazı API lar sadece bu event gerçekleştikten sonra kullanılabilir.
|
||||
|
||||
app.on('ready', createWindow)
|
||||
|
||||
// Eğer tüm pencereler kapandıysa, çıkış yap.
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (win === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// Bu sayfada, uygulamanızın spesifik main process kodlarını dahil edebilirsiniz.
|
||||
// Aynı zamanda bu kodları ayrı dosyalar halinde oluştura bilir
|
||||
// ve buraya require yoluyla ekleye bilirsiniz.
|
||||
|
||||
```
|
||||
|
||||
Son olarak `index.html` yani göstermek istediğiniz web sayfası:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
We are using node <script>document.write(process.versions.node)</script>,
|
||||
Chrome <script>document.write(process.versions.chrome)</script>,
|
||||
and Electron <script>document.write(process.versions.electron)</script>.
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Uygulamanızı çalıştırın
|
||||
|
||||
`main.js`, `index.html`, ve `package.json` dosyalarını oluşturduktan sonra,
|
||||
uygulamanızı lokal olarak test ederek, doğru çalışıp çalışmadığını
|
||||
test etmek isteye bilirsiniz. O halde aşağıdaki yönergeleri takip edin:
|
||||
|
||||
### `electron`
|
||||
|
||||
[`electron`](https://github.com/electron-userland/electron-prebuilt),
|
||||
Electron'un pre-compiled versiyonunu içeren bir `npm` modülüdür.
|
||||
|
||||
|
||||
Eğer bunu global olarak `npm` yoluyla yüklediyseniz, o halde sadece aşağıdaki komutu
|
||||
uygulamanızın kaynak klasöründe çalıstırmanız yeterlidir:
|
||||
|
||||
```bash
|
||||
electron .
|
||||
```
|
||||
|
||||
Eğer lokal olarak yüklediyseniz, o zaman aşağıda ki gibi
|
||||
çalıştırın:
|
||||
|
||||
#### macOS / Linux
|
||||
|
||||
```bash
|
||||
$ ./node_modules/.bin/electron .
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
```bash
|
||||
$ .\node_modules\.bin\electron .
|
||||
```
|
||||
|
||||
### Manuel olarak indirilmiş Electron mimarisi
|
||||
|
||||
Eğer Electronu manuel olarak indirdiyseniz, aynı zamanda dahili olan
|
||||
mimariyide kullanarak, uygulamanızı çalıştıra bilirsiniz.
|
||||
|
||||
#### Windows
|
||||
|
||||
```bash
|
||||
$ .\electron\electron.exe your-app\
|
||||
```
|
||||
|
||||
#### Linux
|
||||
|
||||
```bash
|
||||
$ ./electron/electron your-app/
|
||||
```
|
||||
|
||||
#### macOS
|
||||
|
||||
```bash
|
||||
$ ./Electron.app/Contents/MacOS/Electron your-app/
|
||||
```
|
||||
|
||||
`Electron.app` Electron un dağı₺tım paketinin bir parçasıdır,
|
||||
bunu [adresinden](https://github.com/electron/electron/releases) indirebilirsiniz.
|
||||
|
||||
### Dağıtım olarak çalıştır
|
||||
|
||||
Uygulamanızı yazdıktan sonra, bir dağıtım oluşturmak için
|
||||
[Application Distribution](./application-distribution.md)
|
||||
sayfasında ki yönergeleri izleyin ve daha sonra arşivlenmiş uygulamayı çalıştırın.
|
||||
|
||||
### Örneği deneyin
|
||||
|
||||
[`electron/electron-quick-start`](https://github.com/electron/electron-quick-start) repository klonlayarak bu eğitimdeki kodu çalıştıra bilirsiniz.
|
||||
|
||||
**Note**: Bu işlemleri uygulamak için [Git](https://git-scm.com) ve [Node.js](https://nodejs.org/en/download/) ([npm](https://npmjs.org) da bununla birlikte gelir) sisteminizde yüklü olması gerekmektedir.
|
||||
|
||||
```bash
|
||||
# Repository klonla
|
||||
$ git clone https://github.com/electron/electron-quick-start
|
||||
# Electron repositorye git
|
||||
$ cd electron-quick-start
|
||||
# Gerekli kütüphaneleri yükle
|
||||
$ npm install
|
||||
# Uygulamayı çalıştır
|
||||
$ npm start
|
||||
```
|
||||
|
||||
Daha fazla örnek uygulama için, harika electron topluluğu tarafından oluşturulan,
|
||||
[list of boilerplates](https://electron.atom.io/community/#boilerplates)
|
||||
sayfasını ziyaret edin.
|
||||
|
||||
[share-data]: ../faq.md#how-to-share-data-between-web-pages
|
|
@ -1,4 +1,7 @@
|
|||
# shell
|
||||
> 使用系统默认应用管理文件和 URL .
|
||||
|
||||
进程: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
`shell` 模块提供了集成其他桌面客户端的关联功能.
|
||||
|
||||
|
@ -11,7 +14,7 @@ const {shell} = require('electron')
|
|||
shell.openExternal('https://github.com')
|
||||
```
|
||||
|
||||
## Methods
|
||||
## 方法
|
||||
|
||||
`shell` 模块包含以下函数:
|
||||
|
||||
|
@ -19,27 +22,60 @@ shell.openExternal('https://github.com')
|
|||
|
||||
* `fullPath` String
|
||||
|
||||
打开文件所在文件夹,一般情况下还会选中它.
|
||||
Returns `Boolean` -
|
||||
是否成功打开文件所在文件夹,一般情况下还会选中它.
|
||||
|
||||
### `shell.openItem(fullPath)`
|
||||
|
||||
* `fullPath` String
|
||||
|
||||
以默认打开方式打开文件.
|
||||
Returns `Boolean` - 是否成功的以默认打开方式打开文件.
|
||||
|
||||
|
||||
### `shell.openExternal(url)`
|
||||
|
||||
* `url` String
|
||||
* `options` Object (可选) _macOS_
|
||||
* `activate` Boolean - `true` 让打开的应用在前面显示,默认为 `true`.
|
||||
* `callback` Function (可选) - 如果指定将执行异步打开. _macOS_
|
||||
* `error` Error
|
||||
|
||||
以系统默认设置打开外部协议.(例如,mailto: somebody@somewhere.io会打开用户默认的邮件客户端)
|
||||
Returns `Boolean` - 应用程序是否打开URL.如果指定了 callback 回调方法, 则返回 true.
|
||||
|
||||
以系统默认设置打开外部协议.(例如,mailto: URLs 会打开用户默认的邮件客户端)
|
||||
|
||||
|
||||
### `shell.moveItemToTrash(fullPath)`
|
||||
|
||||
* `fullPath` String
|
||||
|
||||
Returns `Boolean` - 文件是否成功移动到垃圾桶
|
||||
|
||||
删除指定路径文件,并返回此操作的状态值(boolean类型).
|
||||
|
||||
### `shell.beep()`
|
||||
|
||||
播放 beep 声音.
|
||||
|
||||
### `shell.writeShortcutLink(shortcutPath[, operation], options)` _Windows_
|
||||
|
||||
* `shortcutPath` String
|
||||
* `operation` String (可选) - 默认为 `create`, 可以为下列的值:
|
||||
* `create` - 创建一个新的快捷方式,如果存在的话会覆盖.
|
||||
* `update` - 仅在现有快捷方式上更新指定属性.
|
||||
* `replace` - 覆盖现有的快捷方式,如果快捷方式不存在则会失败.
|
||||
* `options` [ShortcutDetails](structures/shortcut-details.md)
|
||||
|
||||
Returns `Boolean` - 快捷方式是否成功创建
|
||||
|
||||
为 `shortcutPath` 创建或更新快捷链接.
|
||||
|
||||
### `shell.readShortcutLink(shortcutPath)` _Windows_
|
||||
|
||||
* `shortcutPath` String
|
||||
|
||||
Returns [`ShortcutDetails`](structures/shortcut-details.md)
|
||||
|
||||
读取 `shortcutPath` 的快捷连接的信息.
|
||||
|
||||
发生错误时,会抛出异常信息.
|
||||
|
|
|
@ -377,6 +377,11 @@ window.onbeforeunload = (e) => {
|
|||
Emitted when the window is closed. After you have received this event you should
|
||||
remove the reference to the window and avoid using it any more.
|
||||
|
||||
#### Event: 'session-end' _Windows_
|
||||
|
||||
Emitted when window session is going to end due to force shutdown or machine restart
|
||||
or session log off.
|
||||
|
||||
#### Event: 'unresponsive'
|
||||
|
||||
Emitted when the web page becomes unresponsive.
|
||||
|
@ -499,6 +504,14 @@ Returns:
|
|||
|
||||
Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, `left`.
|
||||
|
||||
#### Event: 'sheet-begin' _macOS_
|
||||
|
||||
Emitted when the window opens a sheet.
|
||||
|
||||
#### Event: 'sheet-end' _macOS_
|
||||
|
||||
Emitted when the window has closed a sheet.
|
||||
|
||||
### Static Methods
|
||||
|
||||
The `BrowserWindow` class has the following static methods:
|
||||
|
|
|
@ -104,3 +104,9 @@ on complete.
|
|||
|
||||
Removes the cookies matching `url` and `name`, `callback` will called with
|
||||
`callback()` on complete.
|
||||
|
||||
#### `cookies.flushStore(callback)`
|
||||
|
||||
* `callback` Function
|
||||
|
||||
Writes any unwritten cookies data to disk.
|
||||
|
|
|
@ -100,6 +100,8 @@ Returns `Boolean` - Whether the download is paused.
|
|||
|
||||
Resumes the download that has been paused.
|
||||
|
||||
**Note:** To enable resumable downloads the server you are downloading from must support range requests and provide both `Last-Modified` and `ETag` header values. Otherwise `resume()` will dismiss previously received bytes and restart the download from the beginning.
|
||||
|
||||
#### `downloadItem.canResume()`
|
||||
|
||||
Resumes `Boolean` - Whether the download can resume.
|
||||
|
|
|
@ -70,7 +70,7 @@ The `role` property can have following values:
|
|||
* `editMenu` - Whole default "Edit" menu (Undo, Copy, etc.)
|
||||
* `windowMenu` - Whole default "Window" menu (Minimize, Close, etc.)
|
||||
|
||||
The following additional roles are avaiable on macOS:
|
||||
The following additional roles are available on macOS:
|
||||
|
||||
* `about` - Map to the `orderFrontStandardAboutPanel` action
|
||||
* `hide` - Map to the `hide` action
|
||||
|
@ -120,4 +120,4 @@ A String representing the menu items visible label
|
|||
|
||||
#### `menuItem.click`
|
||||
|
||||
A Function that is fired when the MenuItem recieves a click event
|
||||
A Function that is fired when the MenuItem receives a click event
|
||||
|
|
|
@ -28,6 +28,10 @@ effect on macOS.
|
|||
|
||||
Returns `Menu` - The application menu, if set, or `null`, if not set.
|
||||
|
||||
**Note:** The returned `Menu` instance doesn't support dynamic addition or
|
||||
removal of menu items. [Instance properties](#instance-properties) can still
|
||||
be dynamically modified.
|
||||
|
||||
#### `Menu.sendActionToFirstResponder(action)` _macOS_
|
||||
|
||||
* `action` String
|
||||
|
|
|
@ -11,6 +11,7 @@ Process: [Main](../tutorial/quick-start.md#main-process)
|
|||
* `backgroundColor` String (optional) - Button background color in hex format,
|
||||
i.e `#ABCDEF`.
|
||||
* `icon` [NativeImage](native-image.md) (optional) - Button icon.
|
||||
* `iconPosition` String - Can be `left`, `right` or `overlay`.
|
||||
* `click` Function (optional) - Function to call when the button is clicked.
|
||||
|
||||
### Instance Properties
|
||||
|
|
|
@ -16,6 +16,10 @@ Creates a new touch bar with the specified items. Use
|
|||
**Note:** The TouchBar API is currently experimental and may change or be
|
||||
removed in future Electron releases.
|
||||
|
||||
**Tip:** If you don't have a MacBook with Touch Bar, you can use
|
||||
[Touch Bar Simulator](https://github.com/sindresorhus/touch-bar-simulator)
|
||||
to test Touch Bar usage in your app.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
The following properties are available on instances of `TouchBar`:
|
||||
|
|
|
@ -12,7 +12,8 @@ rendered.
|
|||
Unlike an `iframe`, the `webview` runs in a separate process than your
|
||||
app. It doesn't have the same permissions as your web page and all interactions
|
||||
between your app and embedded content will be asynchronous. This keeps your app
|
||||
safe from the embedded content.
|
||||
safe from the embedded content. **Note:** Most methods called on the
|
||||
webview from the host page require a syncronous call to the main process.
|
||||
|
||||
For security purposes, `webview` can only be used in `BrowserWindow`s that have
|
||||
`nodeIntegration` enabled.
|
||||
|
|
|
@ -30,6 +30,10 @@ has to be a field of `BrowserWindow`'s options.
|
|||
|
||||
* Node integration will always be disabled in the opened `window` if it is
|
||||
disabled on the parent window.
|
||||
* Context isolation will always be enabled in the opened `window` if it is
|
||||
enabled on the parent window.
|
||||
* JavaScript will always be disabled in the opened `window` if it is disabled on
|
||||
the parent window.
|
||||
* Non-standard features (that are not handled by Chromium or Electron) given in
|
||||
`features` will be passed to any registered `webContent`'s `new-window` event
|
||||
handler in the `additionalFeatures` argument.
|
||||
|
|
|
@ -10,6 +10,9 @@ Follow the guidelines below for building Electron on Windows.
|
|||
* [Python 2.7](http://www.python.org/download/releases/2.7/)
|
||||
* [Node.js](http://nodejs.org/download/)
|
||||
* [Git](http://git-scm.com)
|
||||
* [Debugging Tools for Windows](https://msdn.microsoft.com/en-us/library/windows/hardware/ff551063.aspx)
|
||||
if you plan on creating a full distribution since `symstore.exe` is used for
|
||||
creating a symbol store from `.pdb` files.
|
||||
|
||||
If you don't currently have a Windows installation,
|
||||
[dev.microsoftedge.com](https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/)
|
||||
|
|
|
@ -148,7 +148,7 @@ npm uninstall electron
|
|||
npm uninstall -g electron
|
||||
```
|
||||
|
||||
However if your are using the built-in module but still getting this error, it
|
||||
However if you are using the built-in module but still getting this error, it
|
||||
is very likely you are using the module in the wrong process. For example
|
||||
`electron.app` can only be used in the main process, while `electron.webFrame`
|
||||
is only available in renderer processes.
|
||||
|
|
|
@ -36,8 +36,8 @@ are fine differences.
|
|||
* On Windows 8.1 and Windows 8, a shortcut to your app, with a [Application User
|
||||
Model ID][app-user-model-id], must be installed to the Start screen. Note,
|
||||
however, that it does not need to be pinned to the Start screen.
|
||||
* On Windows 7, notifications are not supported. You can however send
|
||||
"balloon notifications" using the [Tray API][tray-balloon].
|
||||
* On Windows 7, notifications work via a custom implemetation which visually
|
||||
resembles the native one on newer systems.
|
||||
|
||||
Furthermore, the maximum length for the notification body is 250 characters,
|
||||
with the Windows team recommending that notifications should be kept to 200
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '1.6.6',
|
||||
'version%': '1.6.7',
|
||||
'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c',
|
||||
},
|
||||
'includes': [
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
'default_app/index.html',
|
||||
'default_app/main.js',
|
||||
'default_app/package.json',
|
||||
'default_app/renderer.js',
|
||||
],
|
||||
'lib_sources': [
|
||||
'atom/app/atom_content_client.cc',
|
||||
|
|
|
@ -12,11 +12,7 @@ const {EventEmitter} = require('events')
|
|||
|
||||
Object.setPrototypeOf(App.prototype, EventEmitter.prototype)
|
||||
|
||||
let appPath = null
|
||||
|
||||
Object.assign(app, {
|
||||
getAppPath () { return appPath },
|
||||
setAppPath (path) { appPath = path },
|
||||
setApplicationMenu (menu) {
|
||||
return Menu.setApplicationMenu(menu)
|
||||
},
|
||||
|
|
|
@ -159,10 +159,11 @@ TouchBar.TouchBarButton = class TouchBarButton extends TouchBarItem {
|
|||
super()
|
||||
if (config == null) config = {}
|
||||
this.type = 'button'
|
||||
const {click, icon, label, backgroundColor} = config
|
||||
const {click, icon, iconPosition, label, backgroundColor} = config
|
||||
this._addLiveProperty('label', label)
|
||||
this._addLiveProperty('backgroundColor', backgroundColor)
|
||||
this._addLiveProperty('icon', icon)
|
||||
this._addLiveProperty('iconPosition', iconPosition)
|
||||
if (typeof click === 'function') {
|
||||
this.onInteraction = () => {
|
||||
config.click()
|
||||
|
|
|
@ -5,7 +5,7 @@ const {isSameOrigin} = process.atomBinding('v8_util')
|
|||
const parseFeaturesString = require('../common/parse-features-string')
|
||||
|
||||
const hasProp = {}.hasOwnProperty
|
||||
const frameToGuest = {}
|
||||
const frameToGuest = new Map()
|
||||
|
||||
// Copy attribute of |parent| to |child| if it is not defined in |child|.
|
||||
const mergeOptions = function (child, parent, visited) {
|
||||
|
@ -48,11 +48,16 @@ const mergeBrowserWindowOptions = function (embedder, options) {
|
|||
options.webPreferences.nodeIntegration = false
|
||||
}
|
||||
|
||||
// Enable context isolation on child window if enable on parent window
|
||||
// Enable context isolation on child window if enabled on parent window
|
||||
if (embedder.getWebPreferences().contextIsolation === true) {
|
||||
options.webPreferences.contextIsolation = true
|
||||
}
|
||||
|
||||
// Disable JavaScript on child window if disabled on parent window
|
||||
if (embedder.getWebPreferences().javascript === false) {
|
||||
options.webPreferences.javascript = false
|
||||
}
|
||||
|
||||
// Sets correct openerId here to give correct options to 'new-window' event handler
|
||||
options.webPreferences.openerId = embedder.id
|
||||
|
||||
|
@ -87,10 +92,10 @@ const setupGuest = function (embedder, frameName, guest, options) {
|
|||
guest.once('closed', closedByUser)
|
||||
}
|
||||
if (frameName) {
|
||||
frameToGuest[frameName] = guest
|
||||
frameToGuest.set(frameName, guest)
|
||||
guest.frameName = frameName
|
||||
guest.once('closed', function () {
|
||||
delete frameToGuest[frameName]
|
||||
frameToGuest.delete(frameName)
|
||||
})
|
||||
}
|
||||
return guestId
|
||||
|
@ -98,7 +103,7 @@ const setupGuest = function (embedder, frameName, guest, options) {
|
|||
|
||||
// Create a new guest created by |embedder| with |options|.
|
||||
const createGuest = function (embedder, url, frameName, options, postData) {
|
||||
let guest = frameToGuest[frameName]
|
||||
let guest = frameToGuest.get(frameName)
|
||||
if (frameName && (guest != null)) {
|
||||
guest.loadURL(url)
|
||||
return guest.webContents.id
|
||||
|
@ -186,7 +191,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName,
|
|||
const options = {}
|
||||
|
||||
const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor']
|
||||
const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload']
|
||||
const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload', 'javascript', 'contextIsolation']
|
||||
const disposition = 'new-window'
|
||||
|
||||
// Used to store additional features
|
||||
|
@ -197,6 +202,10 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName,
|
|||
if (value === undefined) {
|
||||
additionalFeatures.push(key)
|
||||
} else {
|
||||
// Don't allow webPreferences to be set since it must be an object
|
||||
// that cannot be directly overridden
|
||||
if (key === 'webPreferences') return
|
||||
|
||||
if (webPreferences.includes(key)) {
|
||||
if (options.webPreferences == null) {
|
||||
options.webPreferences = {}
|
||||
|
|
|
@ -56,7 +56,7 @@ class CrashReporter {
|
|||
const env = {
|
||||
ELECTRON_INTERNAL_CRASH_SERVICE: 1
|
||||
}
|
||||
spawn(process.execPath, args, {
|
||||
this._crashServiceProcess = spawn(process.execPath, args, {
|
||||
env: env,
|
||||
detached: true
|
||||
})
|
||||
|
|
|
@ -56,6 +56,7 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (ev
|
|||
let nodeIntegration = 'false'
|
||||
let preloadScript = null
|
||||
let isBackgroundPage = false
|
||||
let appPath = null
|
||||
for (let arg of process.argv) {
|
||||
if (arg.indexOf('--guest-instance-id=') === 0) {
|
||||
// This is a guest web view.
|
||||
|
@ -69,13 +70,15 @@ for (let arg of process.argv) {
|
|||
preloadScript = arg.substr(arg.indexOf('=') + 1)
|
||||
} else if (arg === '--background-page') {
|
||||
isBackgroundPage = true
|
||||
} else if (arg.indexOf('--app-path=') === 0) {
|
||||
appPath = arg.substr(arg.indexOf('=') + 1)
|
||||
}
|
||||
}
|
||||
|
||||
if (window.location.protocol === 'chrome-devtools:') {
|
||||
// Override some inspector APIs.
|
||||
require('./inspector')
|
||||
nodeIntegration = 'true'
|
||||
nodeIntegration = 'false'
|
||||
} else if (window.location.protocol === 'chrome-extension:') {
|
||||
// Add implementations of chrome API.
|
||||
require('./chrome-api').injectTo(window.location.hostname, isBackgroundPage, window)
|
||||
|
@ -116,6 +119,11 @@ if (nodeIntegration === 'true') {
|
|||
} else {
|
||||
global.__filename = __filename
|
||||
global.__dirname = __dirname
|
||||
|
||||
if (appPath) {
|
||||
// Search for module under the app directory
|
||||
module.paths = module.paths.concat(Module._nodeModulePaths(appPath))
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect window.onerror to uncaughtException.
|
||||
|
|
|
@ -32,6 +32,13 @@ const resolveURL = function (url) {
|
|||
return a.href
|
||||
}
|
||||
|
||||
// Use this method to ensure values expected as strings in the main process
|
||||
// are convertible to strings in the renderer process. This ensures exceptions
|
||||
// converting values to strings are thrown in this process.
|
||||
const toString = (value) => {
|
||||
return value != null ? `${value}` : value
|
||||
}
|
||||
|
||||
const windowProxies = {}
|
||||
|
||||
const getOrCreateProxy = (ipcRenderer, guestId) => {
|
||||
|
@ -82,7 +89,7 @@ function BrowserWindowProxy (ipcRenderer, guestId) {
|
|||
}
|
||||
|
||||
this.postMessage = (message, targetOrigin) => {
|
||||
ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', guestId, message, targetOrigin, window.location.origin)
|
||||
ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', guestId, message, toString(targetOrigin), window.location.origin)
|
||||
}
|
||||
|
||||
this.eval = (...args) => {
|
||||
|
@ -113,7 +120,7 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage, usesNative
|
|||
if (url != null && url !== '') {
|
||||
url = resolveURL(url)
|
||||
}
|
||||
const guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, features)
|
||||
const guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, toString(frameName), toString(features))
|
||||
if (guestId != null) {
|
||||
return getOrCreateProxy(ipcRenderer, guestId)
|
||||
} else {
|
||||
|
@ -123,11 +130,11 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage, usesNative
|
|||
}
|
||||
|
||||
window.alert = function (message, title) {
|
||||
ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', message, title)
|
||||
ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', toString(message), toString(title))
|
||||
}
|
||||
|
||||
window.confirm = function (message, title) {
|
||||
return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', message, title)
|
||||
return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', toString(message), toString(title))
|
||||
}
|
||||
|
||||
// But we do not support prompt().
|
||||
|
@ -159,7 +166,7 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage, usesNative
|
|||
}
|
||||
|
||||
window.history.go = function (offset) {
|
||||
sendHistoryOperation(ipcRenderer, 'goToOffset', offset)
|
||||
sendHistoryOperation(ipcRenderer, 'goToOffset', +offset)
|
||||
}
|
||||
|
||||
defineProperty(window.history, 'length', {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "electron",
|
||||
"version": "1.6.6",
|
||||
"version": "1.6.7",
|
||||
"devDependencies": {
|
||||
"asar": "^0.11.0",
|
||||
"browserify": "^13.1.0",
|
||||
|
|
|
@ -86,8 +86,6 @@ def main():
|
|||
run_script('create-dist.py')
|
||||
run_script('upload.py')
|
||||
else:
|
||||
if PLATFORM == 'win32':
|
||||
os.environ['OUTPUT_TO_FILE'] = 'output.log'
|
||||
run_script('build.py', ['-c', 'D'])
|
||||
if PLATFORM == 'win32' or target_arch == 'x64':
|
||||
run_script('test.py', ['--ci'])
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const assert = require('assert')
|
||||
const autoUpdater = require('electron').remote.autoUpdater
|
||||
const ipcRenderer = require('electron').ipcRenderer
|
||||
const {autoUpdater} = require('electron').remote
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
// Skip autoUpdater tests in MAS build.
|
||||
if (!process.mas) {
|
||||
|
@ -64,5 +64,25 @@ if (!process.mas) {
|
|||
autoUpdater.quitAndInstall()
|
||||
})
|
||||
})
|
||||
|
||||
describe('error event', function () {
|
||||
it('serializes correctly over the remote module', function (done) {
|
||||
if (process.platform === 'linux') {
|
||||
return done()
|
||||
}
|
||||
|
||||
autoUpdater.once('error', function (error) {
|
||||
assert.equal(error instanceof Error, true)
|
||||
assert.deepEqual(Object.getOwnPropertyNames(error), ['stack', 'message', 'name'])
|
||||
done()
|
||||
})
|
||||
|
||||
autoUpdater.setFeedURL('')
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
autoUpdater.checkForUpdates()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1228,6 +1228,54 @@ describe('BrowserWindow module', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('sheet-begin event', function () {
|
||||
if (process.platform !== 'darwin') {
|
||||
return
|
||||
}
|
||||
|
||||
let sheet = null
|
||||
|
||||
afterEach(function () {
|
||||
return closeWindow(sheet, {assertSingleWindow: false}).then(function () { sheet = null })
|
||||
})
|
||||
|
||||
it('emits when window opens a sheet', function (done) {
|
||||
w.show()
|
||||
w.once('sheet-begin', function () {
|
||||
sheet.close()
|
||||
done()
|
||||
})
|
||||
sheet = new BrowserWindow({
|
||||
modal: true,
|
||||
parent: w
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('sheet-end event', function () {
|
||||
if (process.platform !== 'darwin') {
|
||||
return
|
||||
}
|
||||
|
||||
let sheet = null
|
||||
|
||||
afterEach(function () {
|
||||
return closeWindow(sheet, {assertSingleWindow: false}).then(function () { sheet = null })
|
||||
})
|
||||
|
||||
it('emits when window has closed a sheet', function (done) {
|
||||
w.show()
|
||||
sheet = new BrowserWindow({
|
||||
modal: true,
|
||||
parent: w
|
||||
})
|
||||
w.once('sheet-end', function () {
|
||||
done()
|
||||
})
|
||||
sheet.close()
|
||||
})
|
||||
})
|
||||
|
||||
describe('beginFrameSubscription method', function () {
|
||||
// This test is too slow, only test it on CI.
|
||||
if (!isCI) return
|
||||
|
@ -1511,13 +1559,19 @@ describe('BrowserWindow module', function () {
|
|||
// Only implemented on macOS.
|
||||
if (process.platform !== 'darwin') return
|
||||
|
||||
it('can be changed with setKiosk method', function () {
|
||||
it('can be changed with setKiosk method', function (done) {
|
||||
w.destroy()
|
||||
w = new BrowserWindow()
|
||||
w.setKiosk(true)
|
||||
assert.equal(w.isKiosk(), true)
|
||||
w.setKiosk(false)
|
||||
assert.equal(w.isKiosk(), false)
|
||||
|
||||
w.once('enter-full-screen', () => {
|
||||
w.setKiosk(false)
|
||||
assert.equal(w.isKiosk(), false)
|
||||
})
|
||||
w.once('leave-full-screen', () => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -33,8 +33,10 @@ describe('crashReporter module', function () {
|
|||
const generateSpecs = (description, browserWindowOpts) => {
|
||||
describe(description, function () {
|
||||
var w = null
|
||||
var stopServer = null
|
||||
|
||||
beforeEach(function () {
|
||||
stopServer = null
|
||||
w = new BrowserWindow(Object.assign({
|
||||
show: false
|
||||
}, browserWindowOpts))
|
||||
|
@ -44,13 +46,25 @@ describe('crashReporter module', function () {
|
|||
return closeWindow(w).then(function () { w = null })
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
stopCrashService()
|
||||
})
|
||||
|
||||
afterEach(function (done) {
|
||||
if (stopServer != null) {
|
||||
stopServer(done)
|
||||
} else {
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
it('should send minidump when renderer crashes', function (done) {
|
||||
if (process.env.APPVEYOR === 'True') return done()
|
||||
if (process.env.TRAVIS === 'true') return done()
|
||||
|
||||
this.timeout(120000)
|
||||
|
||||
startServer({
|
||||
stopServer = startServer({
|
||||
callback (port) {
|
||||
const crashUrl = url.format({
|
||||
protocol: 'file',
|
||||
|
@ -70,11 +84,26 @@ describe('crashReporter module', function () {
|
|||
|
||||
this.timeout(120000)
|
||||
|
||||
startServer({
|
||||
stopServer = startServer({
|
||||
callback (port) {
|
||||
const crashesDir = path.join(app.getPath('temp'), `${app.getName()} Crashes`)
|
||||
const crashesDir = path.join(app.getPath('temp'), `${process.platform === 'win32' ? 'Zombies' : app.getName()} Crashes`)
|
||||
const version = app.getVersion()
|
||||
const crashPath = path.join(fixtures, 'module', 'crash.js')
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
const crashServiceProcess = childProcess.spawn(process.execPath, [
|
||||
`--reporter-url=http://127.0.0.1:${port}`,
|
||||
'--application-name=Zombies',
|
||||
`--crashes-directory=${crashesDir}`
|
||||
], {
|
||||
env: {
|
||||
ELECTRON_INTERNAL_CRASH_SERVICE: 1
|
||||
},
|
||||
detached: true
|
||||
})
|
||||
remote.process.crashServicePid = crashServiceProcess.pid
|
||||
}
|
||||
|
||||
childProcess.fork(crashPath, [port, version, crashesDir], {silent: true})
|
||||
},
|
||||
processType: 'browser',
|
||||
|
@ -85,7 +114,6 @@ describe('crashReporter module', function () {
|
|||
it('should not send minidump if uploadToServer is false', function (done) {
|
||||
this.timeout(120000)
|
||||
|
||||
let server
|
||||
let dumpFile
|
||||
let crashesDir = crashReporter.getCrashesDirectory()
|
||||
const existingDumpFiles = new Set()
|
||||
|
@ -96,9 +124,8 @@ describe('crashReporter module', function () {
|
|||
}
|
||||
const testDone = (uploaded) => {
|
||||
if (uploaded) {
|
||||
return done(new Error('fail'))
|
||||
return done(new Error('Uploaded crash report'))
|
||||
}
|
||||
server.close()
|
||||
if (process.platform === 'darwin') {
|
||||
crashReporter.setUploadToServer(true)
|
||||
}
|
||||
|
@ -139,7 +166,7 @@ describe('crashReporter module', function () {
|
|||
})
|
||||
})
|
||||
|
||||
server = startServer({
|
||||
stopServer = startServer({
|
||||
callback (port) {
|
||||
const crashUrl = url.format({
|
||||
protocol: 'file',
|
||||
|
@ -157,9 +184,9 @@ describe('crashReporter module', function () {
|
|||
if (process.env.APPVEYOR === 'True') return done()
|
||||
if (process.env.TRAVIS === 'true') return done()
|
||||
|
||||
this.timeout(10000)
|
||||
this.timeout(120000)
|
||||
|
||||
startServer({
|
||||
stopServer = startServer({
|
||||
callback (port) {
|
||||
const crashUrl = url.format({
|
||||
protocol: 'file',
|
||||
|
@ -176,7 +203,7 @@ describe('crashReporter module', function () {
|
|||
}
|
||||
|
||||
generateSpecs('without sandbox', {})
|
||||
generateSpecs('with sandbox ', {
|
||||
generateSpecs('with sandbox', {
|
||||
webPreferences: {
|
||||
sandbox: true,
|
||||
preload: path.join(fixtures, 'module', 'preload-sandbox.js')
|
||||
|
@ -254,7 +281,6 @@ const waitForCrashReport = () => {
|
|||
const startServer = ({callback, processType, done}) => {
|
||||
var called = false
|
||||
var server = http.createServer((req, res) => {
|
||||
server.close()
|
||||
var form = new multiparty.Form()
|
||||
form.parse(req, (error, fields) => {
|
||||
if (error) throw error
|
||||
|
@ -283,6 +309,15 @@ const startServer = ({callback, processType, done}) => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
const activeConnections = new Set()
|
||||
server.on('connection', (connection) => {
|
||||
activeConnections.add(connection)
|
||||
connection.once('close', () => {
|
||||
activeConnections.delete(connection)
|
||||
})
|
||||
})
|
||||
|
||||
let {port} = remote.process
|
||||
server.listen(port, '127.0.0.1', () => {
|
||||
port = server.address().port
|
||||
|
@ -295,5 +330,27 @@ const startServer = ({callback, processType, done}) => {
|
|||
}
|
||||
callback(port)
|
||||
})
|
||||
return server
|
||||
|
||||
return function stopServer (done) {
|
||||
for (const connection of activeConnections) {
|
||||
connection.destroy()
|
||||
}
|
||||
server.close(function () {
|
||||
done()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const stopCrashService = () => {
|
||||
const {crashServicePid} = remote.process
|
||||
if (crashServicePid) {
|
||||
remote.process.crashServicePid = 0
|
||||
try {
|
||||
process.kill(crashServicePid)
|
||||
} catch (error) {
|
||||
if (error.code !== 'ESRCH') {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -219,6 +219,21 @@ describe('session module', function () {
|
|||
if (error) return done(error)
|
||||
})
|
||||
})
|
||||
|
||||
describe('ses.cookies.flushStore(callback)', function () {
|
||||
it('flushes the cookies to disk and invokes the callback when done', function (done) {
|
||||
session.defaultSession.cookies.set({
|
||||
url: url,
|
||||
name: 'foo',
|
||||
value: 'bar'
|
||||
}, (error) => {
|
||||
if (error) return done(error)
|
||||
session.defaultSession.cookies.flushStore(() => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('ses.clearStorageData(options)', function () {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const assert = require('assert')
|
||||
const path = require('path')
|
||||
const {BrowserWindow, TouchBar} = require('electron').remote
|
||||
const {closeWindow} = require('./window-helpers')
|
||||
|
||||
|
@ -48,6 +49,11 @@ describe('TouchBar module', function () {
|
|||
const label = new TouchBarLabel({label: 'bar'})
|
||||
const touchBar = new TouchBar([
|
||||
new TouchBarButton({label: 'foo', backgroundColor: '#F00', click: () => {}}),
|
||||
new TouchBarButton({
|
||||
icon: path.join(__dirname, 'fixtures', 'assets', 'logo.png'),
|
||||
iconPosition: 'right',
|
||||
click: () => {}
|
||||
}),
|
||||
new TouchBarColorPicker({selectedColor: '#F00', change: () => {}}),
|
||||
new TouchBarGroup({items: new TouchBar([new TouchBarLabel({label: 'hello'})])}),
|
||||
label,
|
||||
|
|
|
@ -13,6 +13,7 @@ const isCI = remote.getGlobal('isCi')
|
|||
describe('chromium feature', function () {
|
||||
var fixtures = path.resolve(__dirname, 'fixtures')
|
||||
var listener = null
|
||||
let w = null
|
||||
|
||||
afterEach(function () {
|
||||
if (listener != null) {
|
||||
|
@ -21,6 +22,10 @@ describe('chromium feature', function () {
|
|||
listener = null
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
return closeWindow(w).then(function () { w = null })
|
||||
})
|
||||
|
||||
describe('heap snapshot', function () {
|
||||
it('does not crash', function () {
|
||||
if (process.env.TRAVIS === 'true') return
|
||||
|
@ -44,11 +49,6 @@ describe('chromium feature', function () {
|
|||
|
||||
describe('document.hidden', function () {
|
||||
var url = 'file://' + fixtures + '/pages/document-hidden.html'
|
||||
var w = null
|
||||
|
||||
afterEach(function () {
|
||||
return closeWindow(w).then(function () { w = null })
|
||||
})
|
||||
|
||||
it('is set correctly when window is not shown', function (done) {
|
||||
w = new BrowserWindow({
|
||||
|
@ -90,13 +90,7 @@ describe('chromium feature', function () {
|
|||
})
|
||||
|
||||
describe('navigator.mediaDevices', function () {
|
||||
if (process.env.TRAVIS === 'true') {
|
||||
return
|
||||
}
|
||||
if (isCI && process.platform === 'linux') {
|
||||
return
|
||||
}
|
||||
if (isCI && process.platform === 'win32') {
|
||||
if (isCI) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -107,7 +101,7 @@ describe('chromium feature', function () {
|
|||
if (labelFound) {
|
||||
done()
|
||||
} else {
|
||||
done('No device labels found: ' + JSON.stringify(labels))
|
||||
done(new Error(`No device labels found: ${JSON.stringify(labels)}`))
|
||||
}
|
||||
}).catch(done)
|
||||
})
|
||||
|
@ -119,7 +113,7 @@ describe('chromium feature', function () {
|
|||
}
|
||||
const deviceIds = []
|
||||
const ses = session.fromPartition('persist:media-device-id')
|
||||
let w = new BrowserWindow({
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
session: ses
|
||||
|
@ -155,11 +149,6 @@ describe('chromium feature', function () {
|
|||
|
||||
describe('navigator.serviceWorker', function () {
|
||||
var url = 'file://' + fixtures + '/pages/service-worker/index.html'
|
||||
var w = null
|
||||
|
||||
afterEach(function () {
|
||||
return closeWindow(w).then(function () { w = null })
|
||||
})
|
||||
|
||||
it('should register for file scheme', function (done) {
|
||||
w = new BrowserWindow({
|
||||
|
@ -188,12 +177,6 @@ describe('chromium feature', function () {
|
|||
return
|
||||
}
|
||||
|
||||
let w = null
|
||||
|
||||
afterEach(() => {
|
||||
return closeWindow(w).then(function () { w = null })
|
||||
})
|
||||
|
||||
it('returns a BrowserWindowProxy object', function () {
|
||||
var b = window.open('about:blank', '', 'show=no')
|
||||
assert.equal(b.closed, false)
|
||||
|
@ -246,6 +229,45 @@ describe('chromium feature', function () {
|
|||
b = window.open(windowUrl, '', 'nodeIntegration=no,show=no')
|
||||
})
|
||||
|
||||
it('disables node integration when it is disabled on the parent window for chrome devtools URLs', function (done) {
|
||||
var b
|
||||
app.once('web-contents-created', (event, contents) => {
|
||||
contents.once('did-finish-load', () => {
|
||||
contents.executeJavaScript('typeof process').then((typeofProcessGlobal) => {
|
||||
assert.equal(typeofProcessGlobal, 'undefined')
|
||||
b.close()
|
||||
done()
|
||||
}).catch(done)
|
||||
})
|
||||
})
|
||||
b = window.open('chrome-devtools://devtools/bundled/inspector.html', '', 'nodeIntegration=no,show=no')
|
||||
})
|
||||
|
||||
it('disables JavaScript when it is disabled on the parent window', function (done) {
|
||||
var b
|
||||
app.once('web-contents-created', (event, contents) => {
|
||||
contents.once('did-finish-load', () => {
|
||||
app.once('browser-window-created', (event, window) => {
|
||||
const preferences = window.webContents.getWebPreferences()
|
||||
assert.equal(preferences.javascript, false)
|
||||
window.destroy()
|
||||
b.close()
|
||||
done()
|
||||
})
|
||||
// Click link on page
|
||||
contents.sendInputEvent({type: 'mouseDown', clickCount: 1, x: 1, y: 1})
|
||||
contents.sendInputEvent({type: 'mouseUp', clickCount: 1, x: 1, y: 1})
|
||||
})
|
||||
})
|
||||
|
||||
var windowUrl = require('url').format({
|
||||
pathname: `${fixtures}/pages/window-no-javascript.html`,
|
||||
protocol: 'file',
|
||||
slashes: true
|
||||
})
|
||||
b = window.open(windowUrl, '', 'javascript=no,show=no')
|
||||
})
|
||||
|
||||
it('does not override child options', function (done) {
|
||||
var b, size
|
||||
size = {
|
||||
|
@ -339,15 +361,48 @@ describe('chromium feature', function () {
|
|||
})
|
||||
b = window.open()
|
||||
})
|
||||
|
||||
it('throws an exception when the arguments cannot be converted to strings', function () {
|
||||
assert.throws(function () {
|
||||
window.open('', {toString: null})
|
||||
}, /Cannot convert object to primitive value/)
|
||||
|
||||
assert.throws(function () {
|
||||
window.open('', '', {toString: 3})
|
||||
}, /Cannot convert object to primitive value/)
|
||||
})
|
||||
|
||||
it('sets the window title to the specified frameName', function (done) {
|
||||
let b
|
||||
app.once('browser-window-created', (event, createdWindow) => {
|
||||
assert.equal(createdWindow.getTitle(), 'hello')
|
||||
b.close()
|
||||
done()
|
||||
})
|
||||
b = window.open('', 'hello')
|
||||
})
|
||||
|
||||
it('does not throw an exception when the frameName is a built-in object property', function (done) {
|
||||
let b
|
||||
app.once('browser-window-created', (event, createdWindow) => {
|
||||
assert.equal(createdWindow.getTitle(), '__proto__')
|
||||
b.close()
|
||||
done()
|
||||
})
|
||||
b = window.open('', '__proto__')
|
||||
})
|
||||
|
||||
it('does not throw an exception when the features include webPreferences', function () {
|
||||
let b
|
||||
assert.doesNotThrow(function () {
|
||||
b = window.open('', '', 'webPreferences=')
|
||||
})
|
||||
b.close()
|
||||
})
|
||||
})
|
||||
|
||||
describe('window.opener', function () {
|
||||
let url = 'file://' + fixtures + '/pages/window-opener.html'
|
||||
let w = null
|
||||
|
||||
afterEach(function () {
|
||||
return closeWindow(w).then(function () { w = null })
|
||||
})
|
||||
|
||||
it('is null for main window', function (done) {
|
||||
w = new BrowserWindow({
|
||||
|
@ -521,6 +576,14 @@ describe('chromium feature', function () {
|
|||
})
|
||||
b = window.open('file://' + fixtures + '/pages/window-open-postMessage.html', '', 'show=no')
|
||||
})
|
||||
|
||||
it('throws an exception when the targetOrigin cannot be converted to a string', function () {
|
||||
var b = window.open('')
|
||||
assert.throws(function () {
|
||||
b.postMessage('test', {toString: null})
|
||||
}, /Cannot convert object to primitive value/)
|
||||
b.close()
|
||||
})
|
||||
})
|
||||
|
||||
describe('window.opener.postMessage', function () {
|
||||
|
@ -849,7 +912,6 @@ describe('chromium feature', function () {
|
|||
})
|
||||
|
||||
describe('PDF Viewer', function () {
|
||||
let w = null
|
||||
const pdfSource = url.format({
|
||||
pathname: path.join(fixtures, 'assets', 'cat.pdf').replace(/\\/g, '/'),
|
||||
protocol: 'file',
|
||||
|
@ -865,10 +927,6 @@ describe('chromium feature', function () {
|
|||
})
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
return closeWindow(w).then(function () { w = null })
|
||||
})
|
||||
|
||||
it('opens when loading a pdf resource as top level navigation', function (done) {
|
||||
ipcMain.once('pdf-loaded', function (event, success) {
|
||||
if (success) done()
|
||||
|
@ -907,4 +965,36 @@ describe('chromium feature', function () {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('window.alert(message, title)', function () {
|
||||
it('throws an exception when the arguments cannot be converted to strings', function () {
|
||||
assert.throws(function () {
|
||||
window.alert({toString: null})
|
||||
}, /Cannot convert object to primitive value/)
|
||||
|
||||
assert.throws(function () {
|
||||
window.alert('message', {toString: 3})
|
||||
}, /Cannot convert object to primitive value/)
|
||||
})
|
||||
})
|
||||
|
||||
describe('window.confirm(message, title)', function () {
|
||||
it('throws an exception when the arguments cannot be converted to strings', function () {
|
||||
assert.throws(function () {
|
||||
window.confirm({toString: null}, 'title')
|
||||
}, /Cannot convert object to primitive value/)
|
||||
|
||||
assert.throws(function () {
|
||||
window.confirm('message', {toString: 3})
|
||||
}, /Cannot convert object to primitive value/)
|
||||
})
|
||||
})
|
||||
|
||||
describe('window.history.go(offset)', function () {
|
||||
it('throws an exception when the argumnet cannot be converted to a string', function () {
|
||||
assert.throws(function () {
|
||||
window.history.go({toString: null})
|
||||
}, /Cannot convert object to primitive value/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
6
spec/fixtures/api/crash-restart.html
vendored
6
spec/fixtures/api/crash-restart.html
vendored
|
@ -3,7 +3,7 @@
|
|||
<script type="text/javascript" charset="utf-8">
|
||||
|
||||
const {port} = require('url').parse(window.location.href, true).query
|
||||
const {crashReporter} = require('electron')
|
||||
const {crashReporter, ipcRenderer} = require('electron')
|
||||
|
||||
crashReporter.start({
|
||||
productName: 'Zombies',
|
||||
|
@ -18,6 +18,10 @@ crashReporter.start({
|
|||
}
|
||||
})
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
ipcRenderer.sendSync('crash-service-pid', crashReporter._crashServiceProcess.pid)
|
||||
}
|
||||
|
||||
setImmediate(() => {
|
||||
if (process.platform === 'darwin') {
|
||||
crashReporter.setExtraParameter('extra2', 'extra2')
|
||||
|
|
5
spec/fixtures/api/crash.html
vendored
5
spec/fixtures/api/crash.html
vendored
|
@ -16,6 +16,11 @@ crashReporter.start({
|
|||
'extra2': 'extra2',
|
||||
}
|
||||
});
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
ipcRenderer.sendSync('crash-service-pid', crashReporter._crashServiceProcess.pid)
|
||||
}
|
||||
|
||||
if (!uploadToServer) {
|
||||
ipcRenderer.sendSync('list-existing-dumps')
|
||||
}
|
||||
|
|
12
spec/fixtures/pages/window-no-javascript.html
vendored
Normal file
12
spec/fixtures/pages/window-no-javascript.html
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<a href="about:blank>" target="_blank">CLICK</a>
|
||||
</body>
|
||||
</html>
|
|
@ -1,60 +1,63 @@
|
|||
const assert = require('assert')
|
||||
const Module = require('module')
|
||||
const path = require('path')
|
||||
const temp = require('temp')
|
||||
const {remote} = require('electron')
|
||||
const {BrowserWindow} = remote
|
||||
const {closeWindow} = require('./window-helpers')
|
||||
|
||||
describe('third-party module', function () {
|
||||
describe('modules support', function () {
|
||||
var fixtures = path.join(__dirname, 'fixtures')
|
||||
temp.track()
|
||||
|
||||
if (process.platform !== 'win32' || process.execPath.toLowerCase().indexOf('\\out\\d\\') === -1) {
|
||||
describe('runas', function () {
|
||||
it('can be required in renderer', function () {
|
||||
require('runas')
|
||||
describe('third-party module', function () {
|
||||
if (process.platform !== 'win32' || process.execPath.toLowerCase().indexOf('\\out\\d\\') === -1) {
|
||||
describe('runas', function () {
|
||||
it('can be required in renderer', function () {
|
||||
require('runas')
|
||||
})
|
||||
|
||||
it('can be required in node binary', function (done) {
|
||||
var runas = path.join(fixtures, 'module', 'runas.js')
|
||||
var child = require('child_process').fork(runas)
|
||||
child.on('message', function (msg) {
|
||||
assert.equal(msg, 'ok')
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('can be required in node binary', function (done) {
|
||||
var runas = path.join(fixtures, 'module', 'runas.js')
|
||||
var child = require('child_process').fork(runas)
|
||||
child.on('message', function (msg) {
|
||||
assert.equal(msg, 'ok')
|
||||
done()
|
||||
describe('ffi', function () {
|
||||
if (process.platform === 'win32') return
|
||||
|
||||
it('does not crash', function () {
|
||||
var ffi = require('ffi')
|
||||
var libm = ffi.Library('libm', {
|
||||
ceil: ['double', ['double']]
|
||||
})
|
||||
assert.equal(libm.ceil(1.5), 2)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
describe('q', function () {
|
||||
var Q = require('q')
|
||||
describe('Q.when', function () {
|
||||
it('emits the fullfil callback', function (done) {
|
||||
Q(true).then(function (val) {
|
||||
assert.equal(val, true)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('ffi', function () {
|
||||
if (process.platform === 'win32') return
|
||||
|
||||
it('does not crash', function () {
|
||||
var ffi = require('ffi')
|
||||
var libm = ffi.Library('libm', {
|
||||
ceil: ['double', ['double']]
|
||||
describe('coffee-script', function () {
|
||||
it('can be registered and used to require .coffee files', function () {
|
||||
assert.doesNotThrow(function () {
|
||||
require('coffee-script').register()
|
||||
})
|
||||
assert.equal(libm.ceil(1.5), 2)
|
||||
assert.strictEqual(require('./fixtures/module/test.coffee'), true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
describe('q', function () {
|
||||
var Q = require('q')
|
||||
describe('Q.when', function () {
|
||||
it('emits the fullfil callback', function (done) {
|
||||
Q(true).then(function (val) {
|
||||
assert.equal(val, true)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('coffee-script', function () {
|
||||
it('can be registered and used to require .coffee files', function () {
|
||||
assert.doesNotThrow(function () {
|
||||
require('coffee-script').register()
|
||||
})
|
||||
assert.strictEqual(require('./fixtures/module/test.coffee'), true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('global variables', function () {
|
||||
|
@ -76,56 +79,79 @@ describe('third-party module', function () {
|
|||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Module._nodeModulePaths', function () {
|
||||
describe('when the path is inside the resources path', function () {
|
||||
it('does not include paths outside of the resources path', function () {
|
||||
let modulePath = process.resourcesPath
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(process.resourcesPath, 'node_modules')
|
||||
])
|
||||
describe('Module._nodeModulePaths', function () {
|
||||
describe('when the path is inside the resources path', function () {
|
||||
it('does not include paths outside of the resources path', function () {
|
||||
let modulePath = process.resourcesPath
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(process.resourcesPath, 'node_modules')
|
||||
])
|
||||
|
||||
modulePath = process.resourcesPath + '-foo'
|
||||
let nodeModulePaths = Module._nodeModulePaths(modulePath)
|
||||
assert(nodeModulePaths.includes(path.join(modulePath, 'node_modules')))
|
||||
assert(nodeModulePaths.includes(path.join(modulePath, '..', 'node_modules')))
|
||||
modulePath = process.resourcesPath + '-foo'
|
||||
let nodeModulePaths = Module._nodeModulePaths(modulePath)
|
||||
assert(nodeModulePaths.includes(path.join(modulePath, 'node_modules')))
|
||||
assert(nodeModulePaths.includes(path.join(modulePath, '..', 'node_modules')))
|
||||
|
||||
modulePath = path.join(process.resourcesPath, 'foo')
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(process.resourcesPath, 'foo', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules')
|
||||
])
|
||||
modulePath = path.join(process.resourcesPath, 'foo')
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(process.resourcesPath, 'foo', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules')
|
||||
])
|
||||
|
||||
modulePath = path.join(process.resourcesPath, 'node_modules', 'foo')
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules')
|
||||
])
|
||||
modulePath = path.join(process.resourcesPath, 'node_modules', 'foo')
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules')
|
||||
])
|
||||
|
||||
modulePath = path.join(process.resourcesPath, 'node_modules', 'foo', 'bar')
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(process.resourcesPath, 'node_modules', 'foo', 'bar', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules')
|
||||
])
|
||||
modulePath = path.join(process.resourcesPath, 'node_modules', 'foo', 'bar')
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(process.resourcesPath, 'node_modules', 'foo', 'bar', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules')
|
||||
])
|
||||
|
||||
modulePath = path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules', 'bar')
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules', 'bar', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules')
|
||||
])
|
||||
modulePath = path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules', 'bar')
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules', 'bar', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules', 'foo', 'node_modules'),
|
||||
path.join(process.resourcesPath, 'node_modules')
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the path is outside the resources path', function () {
|
||||
it('includes paths outside of the resources path', function () {
|
||||
let modulePath = path.resolve('/foo')
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(modulePath, 'node_modules'),
|
||||
path.resolve('/node_modules')
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the path is outside the resources path', function () {
|
||||
it('includes paths outside of the resources path', function () {
|
||||
let modulePath = path.resolve('/foo')
|
||||
assert.deepEqual(Module._nodeModulePaths(modulePath), [
|
||||
path.join(modulePath, 'node_modules'),
|
||||
path.resolve('/node_modules')
|
||||
])
|
||||
describe('require', () => {
|
||||
describe('when loaded URL is not file: protocol', () => {
|
||||
let w
|
||||
|
||||
beforeEach(() => {
|
||||
w = new BrowserWindow({
|
||||
show: false
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await closeWindow(w)
|
||||
w = null
|
||||
})
|
||||
|
||||
it('searches for module under app directory', async () => {
|
||||
w.loadURL('about:blank')
|
||||
const result = await w.webContents.executeJavaScript('typeof require("q").when')
|
||||
assert.equal(result, 'function')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -85,7 +85,7 @@ describe('node feature', function () {
|
|||
child.stdout.on('data', (chunk) => {
|
||||
data += String(chunk)
|
||||
})
|
||||
child.on('exit', (code) => {
|
||||
child.on('close', (code) => {
|
||||
assert.equal(code, 0)
|
||||
assert.equal(data, 'pipes stdio')
|
||||
done()
|
||||
|
|
|
@ -2,20 +2,15 @@
|
|||
process.throwDeprecation = true
|
||||
|
||||
const electron = require('electron')
|
||||
const app = electron.app
|
||||
const crashReporter = electron.crashReporter
|
||||
const ipcMain = electron.ipcMain
|
||||
const dialog = electron.dialog
|
||||
const BrowserWindow = electron.BrowserWindow
|
||||
const protocol = electron.protocol
|
||||
const webContents = electron.webContents
|
||||
const v8 = require('v8')
|
||||
const {app, BrowserWindow, crashReporter, dialog, ipcMain, protocol, webContents} = electron
|
||||
|
||||
const {Coverage} = require('electabul')
|
||||
|
||||
const Coverage = require('electabul').Coverage
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const url = require('url')
|
||||
const util = require('util')
|
||||
const v8 = require('v8')
|
||||
|
||||
var argv = require('yargs')
|
||||
.boolean('ci')
|
||||
|
@ -24,7 +19,10 @@ var argv = require('yargs')
|
|||
.argv
|
||||
|
||||
var window = null
|
||||
process.port = 0 // will be used by crash-reporter spec.
|
||||
|
||||
// will be used by crash-reporter spec.
|
||||
process.port = 0
|
||||
process.crashServicePid = 0
|
||||
|
||||
v8.setFlagsFromString('--expose_gc')
|
||||
app.commandLine.appendSwitch('js-flags', '--expose_gc')
|
||||
|
@ -100,6 +98,12 @@ app.on('window-all-closed', function () {
|
|||
app.quit()
|
||||
})
|
||||
|
||||
app.on('web-contents-created', (event, contents) => {
|
||||
contents.on('crashed', (event, killed) => {
|
||||
console.log(`webContents ${contents.id} crashed: ${contents.getURL()} (killed=${killed})`)
|
||||
})
|
||||
})
|
||||
|
||||
app.on('ready', function () {
|
||||
// Test if using protocol module would crash.
|
||||
electron.protocol.registerStringProtocol('test-if-crashes', function () {})
|
||||
|
@ -329,6 +333,11 @@ ipcMain.on('navigate-with-pending-entry', (event, id) => {
|
|||
})
|
||||
})
|
||||
|
||||
ipcMain.on('crash-service-pid', (event, pid) => {
|
||||
process.crashServicePid = pid
|
||||
event.returnValue = null
|
||||
})
|
||||
|
||||
// Suspend listeners until the next event and then restore them
|
||||
const suspendListeners = (emitter, eventName, callback) => {
|
||||
const listeners = emitter.listeners(eventName)
|
||||
|
|
Loading…
Reference in a new issue