Merge pull request #6 from atom/master

update as upstream
This commit is contained in:
Heilig Benedek 2016-02-25 23:50:13 +01:00
commit 1282d6eedb
137 changed files with 3684 additions and 2342 deletions

2
ISSUE_TEMPLATE.md Normal file
View file

@ -0,0 +1,2 @@
* Electron version:
* Operating system:

View file

@ -57,6 +57,7 @@ API 레퍼런스가 있습니다. Electron을 빌드 하는 방법과 프로젝
- [중국어 번체](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
- [우크라이나어](https://github.com/atom/electron/tree/master/docs-translations/uk-UA)
- [러시아어](https://github.com/atom/electron/tree/master/docs-translations/ru-RU)
- [프랑스어](https://github.com/atom/electron/tree/master/docs-translations/fr-FR)
## 시작하기

View file

@ -54,6 +54,7 @@ contains documents describing how to build and contribute to Electron.
- [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
- [Ukrainian](https://github.com/atom/electron/tree/master/docs-translations/uk-UA)
- [Russian](https://github.com/atom/electron/tree/master/docs-translations/ru-RU)
- [French](https://github.com/atom/electron/tree/master/docs-translations/fr-FR)
## Quick Start
@ -70,6 +71,7 @@ forums
- [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack
- [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
- [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)*
- [`electron-jp`](https://electron-jp-slackin.herokuapp.com/) *(Japanese)*
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)
for a community maintained list of useful example apps, tools and resources.

View file

@ -4,7 +4,7 @@
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
'version%': '0.36.7',
'version%': '0.36.8',
},
'includes': [
'filenames.gypi',
@ -144,6 +144,7 @@
}, {
'copied_libraries': [
'<(libchromiumcontent_dir)/pdf.dll',
'<(libchromiumcontent_dir)/ffmpeg.dll',
],
}],
],
@ -193,6 +194,7 @@
}, {
'copied_libraries': [
'<(PRODUCT_DIR)/lib/libnode.so',
'<(libchromiumcontent_dir)/libffmpeg.so',
],
}],
],
@ -461,6 +463,7 @@
}, {
'copied_libraries': [
'<(PRODUCT_DIR)/libnode.dylib',
'<(libchromiumcontent_dir)/libffmpeg.dylib',
],
}],
],

View file

@ -218,7 +218,8 @@ WebContents::WebContents(content::WebContents* web_contents)
WebContents::WebContents(v8::Isolate* isolate,
const mate::Dictionary& options)
: request_id_(0) {
: embedder_(nullptr),
request_id_(0) {
// Whether it is a guest WebContents.
bool is_guest = false;
options.Get("isGuest", &is_guest);
@ -273,10 +274,10 @@ WebContents::WebContents(v8::Isolate* isolate,
guest_delegate_->Initialize(this);
NativeWindow* owner_window = nullptr;
WebContents* embedder = nullptr;
if (options.Get("embedder", &embedder) && embedder) {
if (options.Get("embedder", &embedder_) && embedder_) {
// New WebContents's owner_window is the embedder's owner_window.
auto relay = NativeWindowRelay::FromWebContents(embedder->web_contents());
auto relay =
NativeWindowRelay::FromWebContents(embedder_->web_contents());
if (relay)
owner_window = relay->window.get();
}
@ -296,6 +297,7 @@ WebContents::~WebContents() {
// The WebContentsDestroyed will not be called automatically because we
// unsubscribe from webContents before destroying it. So we have to manually
// call it here to make sure "destroyed" event is emitted.
RenderViewDeleted(web_contents()->GetRenderViewHost());
WebContentsDestroyed();
}
}
@ -485,17 +487,7 @@ void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
}
void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
int process_id = render_view_host->GetProcess()->GetID();
Emit("render-view-deleted", process_id);
// process.emit('ATOM_BROWSER_RELEASE_RENDER_VIEW', processId);
// Tell the rpc server that a render view has been deleted and we need to
// release all objects owned by it.
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
node::Environment* env = node::Environment::GetCurrent(isolate());
mate::EmitEvent(isolate(), env->process_object(),
"ATOM_BROWSER_RELEASE_RENDER_VIEW", process_id);
Emit("render-view-deleted", render_view_host->GetProcess()->GetID());
}
void WebContents::RenderProcessGone(base::TerminationStatus status) {
@ -675,9 +667,6 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
// be destroyed on close, and WebContentsDestroyed would be called for it, so
// we need to make sure the api::WebContents is also deleted.
void WebContents::WebContentsDestroyed() {
// The RenderViewDeleted was not called when the WebContents is destroyed.
RenderViewDeleted(web_contents()->GetRenderViewHost());
// This event is only for internal use, which is emitted when WebContents is
// being destroyed.
Emit("will-destroy");
@ -710,6 +699,14 @@ bool WebContents::Equal(const WebContents* web_contents) const {
}
void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
if (!url.is_valid()) {
Emit("did-fail-load",
static_cast<int>(net::ERR_INVALID_URL),
net::ErrorToShortString(net::ERR_INVALID_URL),
url.possibly_invalid_spec());
return;
}
content::NavigationController::LoadURLParams params(url);
GURL http_referrer;
@ -1120,6 +1117,12 @@ v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, session_);
}
content::WebContents* WebContents::HostWebContents() {
if (!embedder_)
return nullptr;
return embedder_->web_contents();
}
v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
if (devtools_web_contents_.IsEmpty())
return v8::Null(isolate);
@ -1203,6 +1206,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetProperty("session", &WebContents::Session)
.SetProperty("hostWebContents", &WebContents::HostWebContents)
.SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents)
.SetProperty("debugger", &WebContents::Debugger);
}

View file

@ -147,6 +147,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
// Properties.
v8::Local<v8::Value> Session(v8::Isolate* isolate);
content::WebContents* HostWebContents();
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
v8::Local<v8::Value> Debugger(v8::Isolate* isolate);
@ -287,6 +288,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
scoped_ptr<WebViewGuestDelegate> guest_delegate_;
// The host webcontents that may contain this webcontents.
WebContents* embedder_;
// The type of current WebContents.
Type type_;

View file

@ -109,7 +109,7 @@ void TranslateOldOptions(v8::Isolate* isolate, v8::Local<v8::Object> options) {
// Converts binary data to Buffer.
v8::Local<v8::Value> ToBuffer(v8::Isolate* isolate, void* val, int size) {
auto buffer = node::Buffer::New(isolate, static_cast<char*>(val), size);
auto buffer = node::Buffer::Copy(isolate, static_cast<char*>(val), size);
if (buffer.IsEmpty())
return v8::Null(isolate);
else

View file

@ -16,7 +16,7 @@ namespace api {
FrameSubscriber::FrameSubscriber(v8::Isolate* isolate,
const gfx::Size& size,
const FrameCaptureCallback& callback)
: isolate_(isolate), size_(size), callback_(callback) {
: isolate_(isolate), size_(size), callback_(callback), weak_factory_(this) {
}
bool FrameSubscriber::ShouldCaptureFrame(
@ -28,7 +28,7 @@ bool FrameSubscriber::ShouldCaptureFrame(
media::PIXEL_FORMAT_YV12,
size_, gfx::Rect(size_), size_, base::TimeDelta());
*callback = base::Bind(&FrameSubscriber::OnFrameDelivered,
base::Unretained(this), *storage);
weak_factory_.GetWeakPtr(), *storage);
return true;
}

View file

@ -6,6 +6,7 @@
#define ATOM_BROWSER_API_FRAME_SUBSCRIBER_H_
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#include "ui/gfx/geometry/size.h"
#include "v8/include/v8.h"
@ -35,6 +36,8 @@ class FrameSubscriber : public content::RenderWidgetHostViewFrameSubscriber {
gfx::Size size_;
FrameCaptureCallback callback_;
base::WeakPtrFactory<FrameSubscriber> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FrameSubscriber);
};

View file

@ -1,6 +1,6 @@
const EventEmitter = require('events').EventEmitter;
const bindings = process.atomBinding('session');
const PERSIST_PERFIX = 'persist:';
const PERSIST_PREFIX = 'persist:';
// Returns the Session from |partition| string.
exports.fromPartition = function(partition) {
@ -10,8 +10,8 @@ exports.fromPartition = function(partition) {
if (partition === '') {
return exports.defaultSession;
}
if (partition.startsWith(PERSIST_PERFIX)) {
return bindings.fromPartition(partition.substr(PERSIST_PERFIX.length), false);
if (partition.startsWith(PERSIST_PREFIX)) {
return bindings.fromPartition(partition.substr(PERSIST_PREFIX.length), false);
} else {
return bindings.fromPartition(partition, true);
}

View file

@ -26,7 +26,8 @@ bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol(
bool has_user_gesture) {
GURL escaped_url(net::EscapeExternalHandlerValue(url.spec()));
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(base::IgnoreResult(platform_util::OpenExternal), escaped_url));
base::Bind(
base::IgnoreResult(platform_util::OpenExternal), escaped_url, true));
return true;
}

View file

@ -9,13 +9,15 @@ app.on('window-all-closed', function() {
app.quit();
});
app.on('ready', function() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
useContentSize: true,
exports.load = function(appUrl) {
app.on('ready', function() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
useContentSize: true,
});
mainWindow.loadURL(appUrl);
mainWindow.focus();
});
mainWindow.loadURL('file://' + __dirname + '/index.html');
mainWindow.focus();
});
};

View file

@ -3,31 +3,39 @@
<title>Electron</title>
<style>
body {
color: #555;
font-family: 'Open Sans',Helvetica,Arial,sans-serif;
padding: 30px;
color: #45828E;
background-color: #A5ECFA;
font-family: 'Helvetica Neue', 'Open Sans', Helvetica, Arial, sans-serif;
padding: 0;
margin: 0;
}
.container {
padding: 15px 30px;
}
h2 {
color: #2b6cc2;
font-family: "Crimson Text",Georgia,serif;
background-color: #76C7D7;
color: #FAF7F3;
font-weight: 400;
line-height: 1.1;
letter-spacing: -0.015em;
padding: 15px 30px;
margin: 0;
}
a {
color: #2b6cc2;
color: #39AEC6;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
pre, code {
font-family: "Menlo","Lucida Console",monospace;
border: 1px solid #ddd;
background-color: #f8f8f8;
border: 1px solid #076274;
background-color: #076274;
color: #C5F3FC;
border-radius: 3px;
}
@ -39,19 +47,24 @@
padding: 6px 10px;
}
code {
padding: 1px 4px 1px 4px;
font-size: 13px;
}
#holder {
border: 4px dashed #ccc;
border: 2px dashed #448691;
margin: 0 auto;
height: 300px;
color: #ccc;
color: #45828E;
font-size: 40px;
line-height: 300px;
text-align: center;
-webkit-user-select: none;
}
#holder.hover {
border: 4px dashed #999;
color: #eee;
background-color: #7BDCEF;
}
</style>
</head>
@ -78,40 +91,47 @@
<h2>
<script>
document.write(`Welcome to Electron (v${process.versions.electron})`)
document.write(`Welcome to Electron ${process.versions.electron}`)
</script>
</h2>
<p>
To run your app with Electron, execute the following command under your
Console (or Terminal):
</p>
<div class="container">
<script>document.write('<pre>' + command + '</pre>')</script>
<p>
To run your app with Electron, execute the following command in your
Console (or Terminal):
</p>
<p>
The <code>path-to-your-app</code> should be the path to your own Electron
app, you can read the
<script>
document.write(
`<a href='https://github.com/atom/electron/blob/v${process.versions.electron}/docs/tutorial/quick-start.md'>quick start</a>`
);
</script>
guide in Electron's
<script>
document.write(
`<a href='https://github.com/atom/electron/tree/v${process.versions.electron}/docs#readme'>docs</a>`
);
</script>
on how to write one.
</p>
<script>document.write('<pre>' + command + '</pre>')</script>
<p>
Or you can just drag your app here to run it:
</p>
<p>
The <code>path-to-your-app</code> should be the path to your own Electron
app.
</p>
<p>You can read the
<script>
document.write(
`<a href='https://github.com/atom/electron/blob/v${process.versions.electron}/docs/tutorial/quick-start.md'>quick start</a>`
);
</script>
guide in Electron's
<script>
document.write(
`<a href='https://github.com/atom/electron/tree/v${process.versions.electron}/docs#readme'>docs</a>`
);
</script>
to learn how to write one.
</p>
<p>
Or you can just drag your app here to run it:
</p>
<div id="holder">
Drag your app here to run it
</div>
<div id="holder">
Drag your app here to run it
</div>
<script>

View file

@ -4,8 +4,9 @@ const dialog = electron.dialog;
const shell = electron.shell;
const Menu = electron.Menu;
var fs = require('fs');
var path = require('path');
const fs = require('fs');
const path = require('path');
const url = require('url');
// Quit when all windows are closed and no other one is listening to this.
app.on('window-all-closed', function() {
@ -234,12 +235,10 @@ if (option.modules.length > 0) {
require('module')._preloadModules(option.modules);
}
// Start the specified app if there is one specified in command line, otherwise
// start the default app.
if (option.file && !option.webdriver) {
function loadApplicationPackage(packagePath) {
try {
// Override app name and version.
var packagePath = path.resolve(option.file);
packagePath = path.resolve(packagePath);
var packageJsonPath = path.join(packagePath, 'package.json');
if (fs.existsSync(packageJsonPath)) {
var packageJson = JSON.parse(fs.readFileSync(packageJsonPath));
@ -270,20 +269,44 @@ if (option.file && !option.webdriver) {
throw e;
}
}
}
function loadApplicationByUrl(appUrl) {
require('./default_app').load(appUrl);
}
// Start the specified app if there is one specified in command line, otherwise
// start the default app.
if (option.file && !option.webdriver) {
var file = option.file;
var protocol = url.parse(file).protocol;
var extension = path.extname(file);
if (protocol === 'http:' || protocol === 'https:' || protocol === 'file:') {
loadApplicationByUrl(file);
} else if (extension === '.html' || extension === '.htm') {
loadApplicationByUrl('file://' + path.resolve(file));
} else {
loadApplicationPackage(file);
}
} else if (option.version) {
console.log('v' + process.versions.electron);
process.exit(0);
} else if (option.help) {
var helpMessage = "Electron v" + process.versions.electron + " - Cross Platform Desktop Application Shell\n\n";
helpMessage += "Usage: electron [options] [path]\n\n";
helpMessage += "A path to an Electron application may be specified. The path must be to \n";
helpMessage += "an index.js file or to a folder containing a package.json or index.js file.\n\n";
helpMessage += "Options:\n";
helpMessage += "A path to an Electron application may be specified.\n";
helpMessage += "The path must be one of the following:\n\n";
helpMessage += " - index.js file.\n";
helpMessage += " - Folder containing a package.json file.\n";
helpMessage += " - Folder containing an index.js file.\n";
helpMessage += " - .html/.htm file.\n";
helpMessage += " - http://, https://, or file:// URL.\n";
helpMessage += "\nOptions:\n";
helpMessage += " -r, --require Module to preload (option can be repeated)\n";
helpMessage += " -h, --help Print this usage message.\n";
helpMessage += " -v, --version Print the version.";
console.log(helpMessage);
process.exit(0);
} else {
require('./default_app');
loadApplicationByUrl('file://' + __dirname + '/index.html');
}

View file

@ -54,12 +54,16 @@ app.on('will-quit', function() {
loadedExtensions = Object.keys(extensionInfoMap).map(function(key) {
return extensionInfoMap[key].srcDirectory;
});
try {
fs.mkdirSync(path.dirname(loadedExtensionsPath));
} catch (error) {
// Ignore error
if (loadedExtensions.length > 0) {
try {
fs.mkdirSync(path.dirname(loadedExtensionsPath));
} catch (error) {
// Ignore error
}
fs.writeFileSync(loadedExtensionsPath, JSON.stringify(loadedExtensions));
} else {
fs.unlinkSync(loadedExtensionsPath);
}
return fs.writeFileSync(loadedExtensionsPath, JSON.stringify(loadedExtensions));
} catch (error) {
// Ignore error
}
@ -70,7 +74,7 @@ app.once('ready', function() {
var BrowserWindow, chromeExtensionHandler, i, init, len, protocol, srcDirectory;
protocol = electron.protocol, BrowserWindow = electron.BrowserWindow;
// Load persistented extensions.
// Load persisted extensions.
loadedExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions');
try {
loadedExtensions = JSON.parse(fs.readFileSync(loadedExtensionsPath));

View file

@ -2,6 +2,7 @@ const fs = require('fs');
const path = require('path');
const util = require('util');
const Module = require('module');
const v8 = require('v8');
var slice = [].slice;
@ -129,6 +130,11 @@ if (packageJson.desktopName != null) {
app.setDesktopName((app.getName()) + ".desktop");
}
// Set v8 flags
if (packageJson.v8Flags != null) {
v8.setFlagsFromString(packageJson.v8Flags);
}
// Chrome 42 disables NPAPI plugins by default, reenable them here
app.commandLine.appendSwitch('enable-npapi');

View file

@ -1,13 +1,9 @@
'use strict';
const EventEmitter = require('events').EventEmitter;
const v8Util = process.atomBinding('v8_util');
class ObjectsRegistry extends EventEmitter {
class ObjectsRegistry {
constructor() {
super();
this.setMaxListeners(Number.MAX_VALUE);
this.nextId = 0;
// Stores all objects by ref-counting.
@ -15,70 +11,61 @@ class ObjectsRegistry extends EventEmitter {
this.storage = {};
// Stores the IDs of objects referenced by WebContents.
// (webContentsId) => {(id) => (count)}
// (webContentsId) => [id]
this.owners = {};
}
// Register a new object, the object would be kept referenced until you release
// it explicitly.
add(webContentsId, obj) {
var base, base1, id;
id = this.saveToStorage(obj);
// Register a new object and return its assigned ID. If the object is already
// registered then the already assigned ID would be returned.
add(webContents, obj) {
// Get or assign an ID to the object.
let id = this.saveToStorage(obj);
// Remember the owner.
if ((base = this.owners)[webContentsId] == null) {
base[webContentsId] = {};
// Add object to the set of referenced objects.
let webContentsId = webContents.getId();
let owner = this.owners[webContentsId];
if (!owner) {
owner = this.owners[webContentsId] = new Set();
// Clear the storage when webContents is reloaded/navigated.
webContents.once('render-view-deleted', (event, id) => {
this.clear(id);
});
}
if ((base1 = this.owners[webContentsId])[id] == null) {
base1[id] = 0;
if (!owner.has(id)) {
owner.add(id);
// Increase reference count if not referenced before.
this.storage[id].count++;
}
this.owners[webContentsId][id]++;
// Returns object's id
return id;
}
// Get an object according to its ID.
get(id) {
var ref;
return (ref = this.storage[id]) != null ? ref.object : void 0;
return this.storage[id].object;
}
// Dereference an object according to its ID.
remove(webContentsId, id) {
var pointer;
this.dereference(id, 1);
// Dereference from the storage.
this.dereference(id);
// Also reduce the count in owner.
pointer = this.owners[webContentsId];
if (pointer == null) {
return;
}
--pointer[id];
if (pointer[id] === 0) {
return delete pointer[id];
}
// Also remove the reference in owner.
this.owners[webContentsId].delete(id);
}
// Clear all references to objects refrenced by the WebContents.
clear(webContentsId) {
var count, id, ref;
this.emit("clear-" + webContentsId);
if (this.owners[webContentsId] == null) {
let owner = this.owners[webContentsId];
if (!owner)
return;
}
ref = this.owners[webContentsId];
for (id in ref) {
count = ref[id];
this.dereference(id, count);
}
return delete this.owners[webContentsId];
for (let id of owner)
this.dereference(id);
delete this.owners[webContentsId];
}
// Private: Saves the object into storage and assigns an ID for it.
saveToStorage(object) {
var id;
id = v8Util.getHiddenValue(object, 'atomId');
let id = v8Util.getHiddenValue(object, 'atomId');
if (!id) {
id = ++this.nextId;
this.storage[id] = {
@ -87,18 +74,16 @@ class ObjectsRegistry extends EventEmitter {
};
v8Util.setHiddenValue(object, 'atomId', id);
}
++this.storage[id].count;
return id;
}
// Private: Dereference the object from store.
dereference(id, count) {
var pointer;
pointer = this.storage[id];
dereference(id) {
let pointer = this.storage[id];
if (pointer == null) {
return;
}
pointer.count -= count;
pointer.count -= 1;
if (pointer.count === 0) {
v8Util.deleteHiddenValue(pointer.object, 'atomId');
return delete this.storage[id];

View file

@ -6,11 +6,54 @@ const objectsRegistry = require('./objects-registry');
const v8Util = process.atomBinding('v8_util');
const IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap;
var slice = [].slice;
// The internal properties of Function.
const FUNCTION_PROPERTIES = [
'length', 'name', 'arguments', 'caller', 'prototype',
];
// The remote functions in renderer processes.
// (webContentsId) => {id: Function}
let rendererFunctions = {};
// Return the description of object's members:
let getObjectMemebers = function(object) {
let names = Object.getOwnPropertyNames(object);
// For Function, we should not override following properties even though they
// are "own" properties.
if (typeof object === 'function') {
names = names.filter((name) => {
return !FUNCTION_PROPERTIES.includes(name);
});
}
// Map properties to descriptors.
return names.map((name) => {
let descriptor = Object.getOwnPropertyDescriptor(object, name);
let member = {name, enumerable: descriptor.enumerable, writable: false};
if (descriptor.get === undefined && typeof object[name] === 'function') {
member.type = 'method';
} else {
if (descriptor.set || descriptor.writable)
member.writable = true;
member.type = 'get';
}
return member;
});
};
// Return the description of object's prototype.
let getObjectPrototype = function(object) {
let proto = Object.getPrototypeOf(object);
if (proto === null || proto === Object.prototype)
return null;
return {
members: getObjectMemebers(proto),
proto: getObjectPrototype(proto),
};
};
// Convert a real value into meta data.
var valueToMeta = function(sender, value, optimizeSimpleObject) {
var el, field, i, len, meta, name;
var el, i, len, meta;
if (optimizeSimpleObject == null) {
optimizeSimpleObject = false;
}
@ -57,19 +100,9 @@ var valueToMeta = function(sender, value, optimizeSimpleObject) {
// Reference the original value if it's an object, because when it's
// passed to renderer we would assume the renderer keeps a reference of
// it.
meta.id = objectsRegistry.add(sender.getId(), value);
meta.members = (function() {
var results;
results = [];
for (name in value) {
field = value[name];
results.push({
name: name,
type: typeof field
});
}
return results;
})();
meta.id = objectsRegistry.add(sender, value);
meta.members = getObjectMemebers(value);
meta.proto = getObjectPrototype(value);
} else if (meta.type === 'buffer') {
meta.value = Array.prototype.slice.call(value, 0);
} else if (meta.type === 'promise') {
@ -114,7 +147,7 @@ var exceptionToMeta = function(error) {
var unwrapArgs = function(sender, args) {
var metaToValue;
metaToValue = function(meta) {
var i, len, member, ref, rendererReleased, returnValue;
var i, len, member, ref, returnValue;
switch (meta.type) {
case 'value':
return meta.value;
@ -130,48 +163,50 @@ var unwrapArgs = function(sender, args) {
return Promise.resolve({
then: metaToValue(meta.then)
});
case 'object':
let ret = v8Util.createObjectWithName(meta.name);
case 'object': {
let ret = {};
Object.defineProperty(ret.constructor, 'name', { value: meta.name });
ref = meta.members;
for (i = 0, len = ref.length; i < len; i++) {
member = ref[i];
ret[member.name] = metaToValue(member.value);
}
return ret;
}
case 'function-with-return-value':
returnValue = metaToValue(meta.value);
return function() {
return returnValue;
};
case 'function':
case 'function': {
// Cache the callbacks in renderer.
if (!sender.callbacks) {
sender.callbacks = new IDWeakMap;
sender.on('render-view-deleted', function() {
return this.callbacks.clear();
let webContentsId = sender.getId();
let callbacks = rendererFunctions[webContentsId];
if (!callbacks) {
callbacks = rendererFunctions[webContentsId] = new IDWeakMap;
sender.once('render-view-deleted', function(event, id) {
callbacks.clear();
delete rendererFunctions[id];
});
}
if (sender.callbacks.has(meta.id))
return sender.callbacks.get(meta.id);
// Prevent the callback from being called when its page is gone.
rendererReleased = false;
sender.once('render-view-deleted', function() {
rendererReleased = true;
});
if (callbacks.has(meta.id))
return callbacks.get(meta.id);
let callIntoRenderer = function(...args) {
if (rendererReleased || sender.isDestroyed())
if ((webContentsId in rendererFunctions) && !sender.isDestroyed())
sender.send('ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args));
else
throw new Error(`Attempting to call a function in a renderer window that has been closed or released. Function provided here: ${meta.location}.`);
sender.send('ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args));
};
v8Util.setDestructor(callIntoRenderer, function() {
if (!rendererReleased && !sender.isDestroyed())
if ((webContentsId in rendererFunctions) && !sender.isDestroyed())
sender.send('ATOM_RENDERER_RELEASE_CALLBACK', meta.id);
});
sender.callbacks.set(meta.id, callIntoRenderer);
callbacks.set(meta.id, callIntoRenderer);
return callIntoRenderer;
}
default:
throw new TypeError("Unknown type: " + meta.type);
}
@ -204,11 +239,6 @@ var callFunction = function(event, func, caller, args) {
}
};
// Send by BrowserWindow when its render view is deleted.
process.on('ATOM_BROWSER_RELEASE_RENDER_VIEW', function(id) {
return objectsRegistry.clear(id);
});
ipcMain.on('ATOM_BROWSER_REQUIRE', function(event, module) {
try {
return event.returnValue = valueToMeta(event.sender, process.mainModule.require(module));
@ -246,14 +276,13 @@ ipcMain.on('ATOM_BROWSER_CURRENT_WEB_CONTENTS', function(event) {
});
ipcMain.on('ATOM_BROWSER_CONSTRUCTOR', function(event, id, args) {
var constructor, obj;
try {
args = unwrapArgs(event.sender, args);
constructor = objectsRegistry.get(id);
let constructor = objectsRegistry.get(id);
// Call new with array of arguments.
// http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
obj = new (Function.prototype.bind.apply(constructor, [null].concat(args)));
let obj = new (Function.prototype.bind.apply(constructor, [null].concat(args)));
return event.returnValue = valueToMeta(event.sender, obj);
} catch (error) {
return event.returnValue = exceptionToMeta(error);
@ -261,10 +290,9 @@ ipcMain.on('ATOM_BROWSER_CONSTRUCTOR', function(event, id, args) {
});
ipcMain.on('ATOM_BROWSER_FUNCTION_CALL', function(event, id, args) {
var func;
try {
args = unwrapArgs(event.sender, args);
func = objectsRegistry.get(id);
let func = objectsRegistry.get(id);
return callFunction(event, func, global, args);
} catch (error) {
return event.returnValue = exceptionToMeta(error);
@ -272,13 +300,12 @@ ipcMain.on('ATOM_BROWSER_FUNCTION_CALL', function(event, id, args) {
});
ipcMain.on('ATOM_BROWSER_MEMBER_CONSTRUCTOR', function(event, id, method, args) {
var constructor, obj;
try {
args = unwrapArgs(event.sender, args);
constructor = objectsRegistry.get(id)[method];
let constructor = objectsRegistry.get(id)[method];
// Call new with array of arguments.
obj = new (Function.prototype.bind.apply(constructor, [null].concat(args)));
let obj = new (Function.prototype.bind.apply(constructor, [null].concat(args)));
return event.returnValue = valueToMeta(event.sender, obj);
} catch (error) {
return event.returnValue = exceptionToMeta(error);
@ -286,10 +313,9 @@ ipcMain.on('ATOM_BROWSER_MEMBER_CONSTRUCTOR', function(event, id, method, args)
});
ipcMain.on('ATOM_BROWSER_MEMBER_CALL', function(event, id, method, args) {
var obj;
try {
args = unwrapArgs(event.sender, args);
obj = objectsRegistry.get(id);
let obj = objectsRegistry.get(id);
return callFunction(event, obj[method], obj, args);
} catch (error) {
return event.returnValue = exceptionToMeta(error);
@ -297,9 +323,8 @@ ipcMain.on('ATOM_BROWSER_MEMBER_CALL', function(event, id, method, args) {
});
ipcMain.on('ATOM_BROWSER_MEMBER_SET', function(event, id, name, value) {
var obj;
try {
obj = objectsRegistry.get(id);
let obj = objectsRegistry.get(id);
obj[name] = value;
return event.returnValue = null;
} catch (error) {
@ -308,9 +333,8 @@ ipcMain.on('ATOM_BROWSER_MEMBER_SET', function(event, id, name, value) {
});
ipcMain.on('ATOM_BROWSER_MEMBER_GET', function(event, id, name) {
var obj;
try {
obj = objectsRegistry.get(id);
let obj = objectsRegistry.get(id);
return event.returnValue = valueToMeta(event.sender, obj[name]);
} catch (error) {
return event.returnValue = exceptionToMeta(error);
@ -322,21 +346,18 @@ ipcMain.on('ATOM_BROWSER_DEREFERENCE', function(event, id) {
});
ipcMain.on('ATOM_BROWSER_GUEST_WEB_CONTENTS', function(event, guestInstanceId) {
var guestViewManager;
try {
guestViewManager = require('./guest-view-manager');
let guestViewManager = require('./guest-view-manager');
return event.returnValue = valueToMeta(event.sender, guestViewManager.getGuest(guestInstanceId));
} catch (error) {
return event.returnValue = exceptionToMeta(error);
}
});
ipcMain.on('ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function() {
var args, event, guest, guestInstanceId, guestViewManager, method;
event = arguments[0], guestInstanceId = arguments[1], method = arguments[2], args = 4 <= arguments.length ? slice.call(arguments, 3) : [];
ipcMain.on('ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function(event, guestInstanceId, method, ...args) {
try {
guestViewManager = require('./guest-view-manager');
guest = guestViewManager.getGuest(guestInstanceId);
let guestViewManager = require('./guest-view-manager');
let guest = guestViewManager.getGuest(guestInstanceId);
return guest[method].apply(guest, args);
} catch (error) {
return event.returnValue = exceptionToMeta(error);

View file

@ -892,12 +892,25 @@ void NativeWindowMac::HandleKeyboardEvent(
return;
BOOL handled = [[NSApp mainMenu] performKeyEquivalent:event.os_event];
if (!handled && event.os_event.window != window_.get()) {
// The event comes from detached devtools view, and it has already been
if (!handled && (event.os_event.modifierFlags & NSCommandKeyMask) &&
(event.os_event.keyCode == 50 /* ~ key */)) {
// Handle the cmd+~ shortcut.
Focus(true);
if (!handled && event.os_event.window) {
// Handle the cmd+~ shortcut.
if ((event.os_event.modifierFlags & NSCommandKeyMask) /* cmd */ &&
(event.os_event.keyCode == 50 /* ~ */)) {
// Switch to next visible window.
NSArray* windows = [NSApp windows];
NSIndexSet* indexes = [windows indexesOfObjectsPassingTest:
^BOOL(id window, NSUInteger idx, BOOL* stop) {
return [window isVisible];
}];
if ([indexes count] == 0)
return;
NSUInteger current = [windows indexOfObject:event.os_event.window];
if (current == NSNotFound) // Some faked event.
return;
NSUInteger next = [indexes indexGreaterThanIndex:current];
if (next == NSNotFound)
next = [indexes firstIndex];
[[windows objectAtIndex:next] makeKeyAndOrderFront:nil];
}
}
}

View file

@ -300,14 +300,29 @@ bool NativeWindowViews::IsFocused() {
void NativeWindowViews::Show() {
window_->native_widget_private()->ShowWithWindowState(GetRestoredState());
#if defined(USE_X11)
if (global_menu_bar_)
global_menu_bar_->OnWindowMapped();
#endif
}
void NativeWindowViews::ShowInactive() {
window_->ShowInactive();
#if defined(USE_X11)
if (global_menu_bar_)
global_menu_bar_->OnWindowMapped();
#endif
}
void NativeWindowViews::Hide() {
window_->Hide();
#if defined(USE_X11)
if (global_menu_bar_)
global_menu_bar_->OnWindowUnmapped();
#endif
}
bool NativeWindowViews::IsVisible() {

View file

@ -17,9 +17,9 @@
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>0.36.7</string>
<string>0.36.8</string>
<key>CFBundleShortVersionString</key>
<string>0.36.7</string>
<string>0.36.8</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>

View file

@ -56,8 +56,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,36,7,0
PRODUCTVERSION 0,36,7,0
FILEVERSION 0,36,8,0
PRODUCTVERSION 0,36,8,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -74,12 +74,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "0.36.7"
VALUE "FileVersion", "0.36.8"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "0.36.7"
VALUE "ProductVersion", "0.36.8"
VALUE "SquirrelAwareVersion", "1"
END
END

View file

@ -8,7 +8,9 @@
#include "atom/browser/native_window.h"
#include "base/callback.h"
#include "base/mac/mac_util.h"
#include "base/strings/sys_string_conversions.h"
#include "skia/ext/skia_utils_mac.h"
@interface ModalDelegate : NSObject {
@private
@ -57,7 +59,8 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
int default_id,
const std::string& title,
const std::string& message,
const std::string& detail) {
const std::string& detail,
const gfx::ImageSkia& icon) {
// Ignore the title; it's the window title on other platforms and ignorable.
NSAlert* alert = [[NSAlert alloc] init];
[alert setMessageText:base::SysUTF8ToNSString(message)];
@ -92,6 +95,12 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window,
[[ns_buttons objectAtIndex:default_id] setKeyEquivalent:@"\r"];
}
if (!icon.isNull()) {
NSImage* image = gfx::SkBitmapToNSImageWithColorSpace(
*icon.bitmap(), base::mac::GetGenericRGBColorSpace());
[alert setIcon:image];
}
return alert;
}
@ -113,7 +122,7 @@ int ShowMessageBox(NativeWindow* parent_window,
const gfx::ImageSkia& icon) {
NSAlert* alert = CreateNSAlert(
parent_window, type, buttons, default_id, title, message,
detail);
detail, icon);
// Use runModal for synchronous alert without parent, since we don't have a
// window to wait for.
@ -149,7 +158,7 @@ void ShowMessageBox(NativeWindow* parent_window,
const MessageBoxCallback& callback) {
NSAlert* alert = CreateNSAlert(
parent_window, type, buttons, default_id, title, message,
detail);
detail, icon);
ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback
andAlert:alert
callEndModal:false];

View file

@ -210,6 +210,14 @@ void GlobalMenuBarX11::InitServer(gfx::AcceleratedWidget xid) {
server_ = server_new(path.c_str());
}
void GlobalMenuBarX11::OnWindowMapped() {
GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid_);
}
void GlobalMenuBarX11::OnWindowUnmapped() {
GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid_);
}
void GlobalMenuBarX11::BuildMenuFromModel(ui::MenuModel* model,
DbusmenuMenuitem* parent) {
for (int i = 0; i < model->GetItemCount(); ++i) {

View file

@ -46,6 +46,10 @@ class GlobalMenuBarX11 {
void SetMenu(ui::MenuModel* menu_model);
bool IsServerStarted() const;
// Called by NativeWindow when it show/hides.
void OnWindowMapped();
void OnWindowUnmapped();
private:
// Creates a DbusmenuServer.
void InitServer(gfx::AcceleratedWidget xid);

View file

@ -15,7 +15,7 @@ namespace atom {
namespace {
// Filter out the "&" in menu label.
base::string16 FilterAccecelator(const base::string16& label) {
base::string16 FilterAccelerator(const base::string16& label) {
base::string16 out;
base::RemoveChars(label, base::ASCIIToUTF16("&").c_str(), &out);
return out;
@ -26,7 +26,7 @@ base::string16 FilterAccecelator(const base::string16& label) {
SubmenuButton::SubmenuButton(views::ButtonListener* listener,
const base::string16& title,
views::MenuButtonListener* menu_button_listener)
: views::MenuButton(listener, FilterAccecelator(title),
: views::MenuButton(listener, FilterAccelerator(title),
menu_button_listener, false),
accelerator_(0),
show_underline_(false),

View file

@ -23,7 +23,7 @@ void MediaAccessAllowed(
bool allowed) {
brightray::MediaStreamDevicesController controller(request, callback);
if (allowed)
controller.Accept();
controller.TakeAction();
else
controller.Deny(content::MEDIA_DEVICE_PERMISSION_DENIED);
}

View file

@ -12,12 +12,23 @@
namespace {
bool OpenExternal(const GURL& url, mate::Arguments* args) {
bool activate = true;
if (args->Length() == 2) {
mate::Dictionary options;
if (args->GetNext(&options)) {
options.Get("activate", &activate);
}
}
return platform_util::OpenExternal(url, activate);
}
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("showItemInFolder", &platform_util::ShowItemInFolder);
dict.SetMethod("openItem", &platform_util::OpenItem);
dict.SetMethod("openExternal", &platform_util::OpenExternal);
dict.SetMethod("openExternal", &OpenExternal);
dict.SetMethod("moveItemToTrash", &platform_util::MoveItemToTrash);
dict.SetMethod("beep", &platform_util::Beep);
}

View file

@ -2,49 +2,15 @@
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <map>
#include <string>
#include "atom/common/api/object_life_monitor.h"
#include "atom/common/node_includes.h"
#include "base/stl_util.h"
#include "native_mate/dictionary.h"
#include "v8/include/v8-profiler.h"
namespace {
// A Persistent that can be copied and will not free itself.
template<class T>
struct LeakedPersistentTraits {
typedef v8::Persistent<T, LeakedPersistentTraits<T> > LeakedPersistent;
static const bool kResetInDestructor = false;
template<class S, class M>
static V8_INLINE void Copy(const v8::Persistent<S, M>& source,
LeakedPersistent* dest) {
// do nothing, just allow copy
}
};
// The handles are leaked on purpose.
using FunctionTemplateHandle =
LeakedPersistentTraits<v8::FunctionTemplate>::LeakedPersistent;
std::map<std::string, FunctionTemplateHandle> function_templates_;
v8::Local<v8::Object> CreateObjectWithName(v8::Isolate* isolate,
const std::string& name) {
if (name == "Object")
return v8::Object::New(isolate);
if (ContainsKey(function_templates_, name))
return v8::Local<v8::FunctionTemplate>::New(
isolate, function_templates_[name])->GetFunction()->NewInstance();
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
t->SetClassName(mate::StringToV8(isolate, name));
function_templates_[name] = FunctionTemplateHandle(isolate, t);
return t->GetFunction()->NewInstance();
}
v8::Local<v8::Value> GetHiddenValue(v8::Local<v8::Object> object,
v8::Local<v8::String> key) {
return object->GetHiddenValue(key);
@ -78,7 +44,6 @@ void TakeHeapSnapshot(v8::Isolate* isolate) {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("createObjectWithName", &CreateObjectWithName);
dict.SetMethod("getHiddenValue", &GetHiddenValue);
dict.SetMethod("setHiddenValue", &SetHiddenValue);
dict.SetMethod("deleteHiddenValue", &DeleteHiddenValue);

View file

@ -88,9 +88,13 @@ deprecate.warn = function(oldName, newName) {
return deprecate.log(oldName + " is deprecated. Use " + newName + " instead.");
};
var deprecationHandler = null;
// Print deprecation message.
deprecate.log = function(message) {
if (process.throwDeprecation) {
if (typeof deprecationHandler === 'function') {
deprecationHandler(message);
} else if (process.throwDeprecation) {
throw new Error(message);
} else if (process.traceDeprecation) {
return console.trace(message);
@ -99,4 +103,12 @@ deprecate.log = function(message) {
}
};
deprecate.setHandler = function(handler) {
deprecationHandler = handler;
};
deprecate.getHandler = function() {
return deprecationHandler;
};
module.exports = deprecate;

View file

@ -0,0 +1,11 @@
'use strict';
const deprecate = require('electron').deprecate;
exports.setHandler = function (deprecationHandler) {
deprecate.setHandler(deprecationHandler);
};
exports.getHandler = function () {
return deprecate.getHandler();
};

View file

@ -31,6 +31,12 @@ exports.defineProperties = function(exports) {
return require('../crash-reporter');
}
},
deprecations: {
enumerable: true,
get: function() {
return require('../deprecations');
}
},
nativeImage: {
enumerable: true,
get: function() {

View file

@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 36
#define ATOM_PATCH_VERSION 7
#define ATOM_PATCH_VERSION 8
#define ATOM_VERSION_IS_RELEASE 1

View file

@ -173,6 +173,8 @@ bool Converter<content::StopFindAction>::FromV8(
// static
v8::Local<v8::Value> Converter<content::WebContents*>::ToV8(
v8::Isolate* isolate, content::WebContents* val) {
if (!val)
return v8::Null(isolate);
return atom::api::WebContents::CreateFrom(isolate, val).ToV8();
}

View file

@ -27,7 +27,9 @@ v8::Local<v8::Value> Converter<const net::URLRequest*>::ToV8(
v8::Isolate* isolate, const net::URLRequest* val) {
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
dict->SetString("method", val->method());
dict->SetStringWithoutPathExpansion("url", val->url().spec());
std::string url;
if (!val->url_chain().empty()) url = val->url().spec();
dict->SetStringWithoutPathExpansion("url", url);
dict->SetString("referrer", val->referrer());
scoped_ptr<base::ListValue> list(new base::ListValue);
atom::GetUploadData(list.get(), val);

View file

@ -23,7 +23,7 @@ void OpenItem(const base::FilePath& full_path);
// Open the given external protocol URL in the desktop's default manner.
// (For example, mailto: URLs in the default mail user agent.)
bool OpenExternal(const GURL& url);
bool OpenExternal(const GURL& url, bool activate);
// Move a file to trash.
bool MoveItemToTrash(const base::FilePath& full_path);

View file

@ -64,7 +64,7 @@ void OpenItem(const base::FilePath& full_path) {
XDGOpen(full_path.value());
}
bool OpenExternal(const GURL& url) {
bool OpenExternal(const GURL& url, bool activate) {
if (url.SchemeIs("mailto"))
return XDGEmail(url.spec());
else

View file

@ -119,7 +119,7 @@ void OpenItem(const base::FilePath& full_path) {
}
}
bool OpenExternal(const GURL& url) {
bool OpenExternal(const GURL& url, bool activate) {
DCHECK([NSThread isMainThread]);
NSURL* ns_url = net::NSURLWithGURL(url);
if (!ns_url) {
@ -136,7 +136,15 @@ bool OpenExternal(const GURL& url) {
}
CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us
return [[NSWorkspace sharedWorkspace] openURL:ns_url];
NSUInteger launchOptions = NSWorkspaceLaunchDefault;
if (!activate)
launchOptions |= NSWorkspaceLaunchWithoutActivation;
return [[NSWorkspace sharedWorkspace] openURLs: @[ns_url]
withAppBundleIdentifier: nil
options: launchOptions
additionalEventParamDescriptor: NULL
launchIdentifiers: NULL];
}
bool MoveItemToTrash(const base::FilePath& full_path) {

View file

@ -301,7 +301,7 @@ void OpenItem(const base::FilePath& full_path) {
ui::win::OpenFileViaShell(full_path);
}
bool OpenExternal(const GURL& url) {
bool OpenExternal(const GURL& url, bool activate) {
// Quote the input scheme to be sure that the command does not have
// parameters unexpected by the external program. This url should already
// have been escaped.

View file

@ -1,11 +1,16 @@
'use strict';
const ipcRenderer = require('electron').ipcRenderer;
const CallbacksRegistry = require('electron').CallbacksRegistry;
const v8Util = process.atomBinding('v8_util');
const IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap;
const callbacksRegistry = new CallbacksRegistry;
var includes = [].includes;
var remoteObjectCache = new IDWeakMap;
// Check for circular reference.
var isCircular = function(field, visited) {
if (typeof field === 'object') {
@ -85,9 +90,59 @@ var wrapArgs = function(args, visited) {
return Array.prototype.slice.call(args).map(valueToMeta);
};
// Populate object's members from descriptors.
// This matches |getObjectMemebers| in rpc-server.
let setObjectMembers = function(object, metaId, members) {
for (let member of members) {
if (object.hasOwnProperty(member.name))
continue;
let descriptor = { enumerable: member.enumerable };
if (member.type === 'method') {
let remoteMemberFunction = function() {
if (this && this.constructor === remoteMemberFunction) {
// Constructor call.
let ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments));
return metaToValue(ret);
} else {
// Call member function.
let ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(arguments));
return metaToValue(ret);
}
};
descriptor.value = remoteMemberFunction;
} else if (member.type === 'get') {
descriptor.get = function() {
return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, member.name));
};
// Only set setter when it is writable.
if (member.writable) {
descriptor.set = function(value) {
ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_SET', metaId, member.name, value);
return value;
};
}
}
Object.defineProperty(object, member.name, descriptor);
}
};
// Populate object's prototype from descriptor.
// This matches |getObjectPrototype| in rpc-server.
let setObjectPrototype = function(object, metaId, descriptor) {
if (descriptor === null)
return;
let proto = {};
setObjectMembers(proto, metaId, descriptor.members);
setObjectPrototype(proto, metaId, descriptor.proto);
Object.setPrototypeOf(object, proto);
};
// Convert meta data from browser into real value.
var metaToValue = function(meta) {
var el, i, j, len, len1, member, ref1, ref2, results, ret;
let metaToValue = function(meta) {
var el, i, len, ref1, results, ret;
switch (meta.type) {
case 'value':
return meta.value;
@ -112,56 +167,47 @@ var metaToValue = function(meta) {
case 'exception':
throw new Error(meta.message + "\n" + meta.stack);
default:
if (remoteObjectCache.has(meta.id))
return remoteObjectCache.get(meta.id);
if (meta.type === 'function') {
// A shadow class to represent the remote function object.
ret = (function() {
function RemoteFunction() {
var obj;
if (this.constructor === RemoteFunction) {
// Constructor call.
obj = ipcRenderer.sendSync('ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments));
/*
Returning object in constructor will replace constructed object
with the returned object.
http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
*/
return metaToValue(obj);
} else {
// Function call.
obj = ipcRenderer.sendSync('ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments));
return metaToValue(obj);
}
let remoteFunction = function() {
if (this && this.constructor === remoteFunction) {
// Constructor call.
let obj = ipcRenderer.sendSync('ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments));
// Returning object in constructor will replace constructed object
// with the returned object.
// http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
return metaToValue(obj);
} else {
// Function call.
let obj = ipcRenderer.sendSync('ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments));
return metaToValue(obj);
}
return RemoteFunction;
})();
};
ret = remoteFunction;
} else {
ret = v8Util.createObjectWithName(meta.name);
ret = {};
}
// Polulate delegate members.
ref2 = meta.members;
for (j = 0, len1 = ref2.length; j < len1; j++) {
member = ref2[j];
if (member.type === 'function') {
ret[member.name] = createRemoteMemberFunction(meta.id, member.name);
} else {
Object.defineProperty(ret, member.name, createRemoteMemberProperty(meta.id, member.name));
}
}
// Populate delegate members.
setObjectMembers(ret, meta.id, meta.members);
// Populate delegate prototype.
setObjectPrototype(ret, meta.id, meta.proto);
// Set constructor.name to object's name.
Object.defineProperty(ret.constructor, 'name', { value: meta.name });
// Track delegate object's life time, and tell the browser to clean up
// when the object is GCed.
v8Util.setDestructor(ret, function() {
return ipcRenderer.send('ATOM_BROWSER_DEREFERENCE', meta.id);
ipcRenderer.send('ATOM_BROWSER_DEREFERENCE', meta.id);
});
// Remember object's id.
v8Util.setHiddenValue(ret, 'atomId', meta.id);
remoteObjectCache.set(meta.id, ret);
return ret;
}
};
@ -185,52 +231,6 @@ var metaToPlainObject = function(meta) {
return obj;
};
// Create a RemoteMemberFunction instance.
// This function's content should not be inlined into metaToValue, otherwise V8
// may consider it circular reference.
var createRemoteMemberFunction = function(metaId, name) {
return (function() {
function RemoteMemberFunction() {
var ret;
if (this.constructor === RemoteMemberFunction) {
// Constructor call.
ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, name, wrapArgs(arguments));
return metaToValue(ret);
} else {
// Call member function.
ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CALL', metaId, name, wrapArgs(arguments));
return metaToValue(ret);
}
}
return RemoteMemberFunction;
})();
};
// Create configuration for defineProperty.
// This function's content should not be inlined into metaToValue, otherwise V8
// may consider it circular reference.
var createRemoteMemberProperty = function(metaId, name) {
return {
enumerable: true,
configurable: false,
set: function(value) {
// Set member data.
ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_SET', metaId, name, value);
return value;
},
get: function() {
// Get member data.
return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, name));
}
};
};
// Browser calls a callback in renderer.
ipcRenderer.on('ATOM_RENDERER_CALLBACK', function(event, id, args) {
return callbacksRegistry.apply(id, metaToValue(args));
@ -257,73 +257,33 @@ for (var name in browserModules) {
}
// Get remote module.
// (Just like node's require, the modules are cached permanently, note that this
// is safe leak since the object is not expected to get freed in browser)
var moduleCache = {};
exports.require = function(module) {
var meta;
if (moduleCache[module] != null) {
return moduleCache[module];
}
meta = ipcRenderer.sendSync('ATOM_BROWSER_REQUIRE', module);
return moduleCache[module] = metaToValue(meta);
return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_REQUIRE', module));
};
// Optimize require('electron').
moduleCache.electron = exports;
// Alias to remote.require('electron').xxx.
var builtinCache = {};
exports.getBuiltin = function(module) {
var meta;
if (builtinCache[module] != null) {
return builtinCache[module];
}
meta = ipcRenderer.sendSync('ATOM_BROWSER_GET_BUILTIN', module);
return builtinCache[module] = metaToValue(meta);
return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_GET_BUILTIN', module));
};
// Get current BrowserWindow object.
var windowCache = null;
// Get current BrowserWindow.
exports.getCurrentWindow = function() {
var meta;
if (windowCache != null) {
return windowCache;
}
meta = ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WINDOW');
return windowCache = metaToValue(meta);
return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WINDOW'));
};
// Get current WebContents object.
var webContentsCache = null;
exports.getCurrentWebContents = function() {
var meta;
if (webContentsCache != null) {
return webContentsCache;
}
meta = ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WEB_CONTENTS');
return webContentsCache = metaToValue(meta);
return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WEB_CONTENTS'));
};
// Get a global object in browser.
exports.getGlobal = function(name) {
var meta;
meta = ipcRenderer.sendSync('ATOM_BROWSER_GLOBAL', name);
return metaToValue(meta);
return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_GLOBAL', name));
};
// Get the process object in browser.
var processCache = null;
exports.__defineGetter__('process', function() {
if (processCache == null) {
processCache = exports.getGlobal('process');
}
return processCache;
return exports.getGlobal('process');
});
// Create a funtion that will return the specifed value when called in browser.

View file

@ -388,7 +388,7 @@ var registerWebViewElement = function() {
'downloadURL',
'inspectServiceWorker',
'print',
'printToPDF'
'printToPDF',
];
nonblockMethods = [
'executeJavaScript',
@ -430,6 +430,12 @@ var registerWebViewElement = function() {
proto[m] = createNonBlockHandler(m);
}
// WebContents associated with this webview.
proto.getWebContents = function() {
var internal = v8Util.getHiddenValue(this, 'internal');
return internal.webContents;
};
// Deprecated.
deprecate.rename(proto, 'getUrl', 'getURL');
window.WebView = webFrame.registerEmbedderCustomElement('webview', {

View file

@ -0,0 +1,91 @@
Vérifiez que vous utilisez la bonne version de la documentation.
Le numéro de version devrait faire partie de l'URL de la page.
Si ce n'est pas le cas, vous utilisez probablement la documentation d'une
branche de développement qui peut contenir des changements API qui ne sont pas
compatibles avec votre version d'Electron. Si c'est le cas, vous pouvez changer
de version sur la liste [versions disponibles](http://electron.atom.io/docs/),
ou, si vous utilisez l'interface de GitHub, ouvrez la liste déroulante "Switch
branches/tags" afin de sélectionner le tag de votre version.
## FAQ
Avant de créer un ticket, vérifiez que votre problème n'a pas déjà sa réponse
dans la FAQ :
* [Electron FAQ](faq/electron-faq.md)
## Guides
* [Plateformes supportées](tutorial/supported-platforms.md)
* [Distribution de l'Application](tutorial/application-distribution.md)
* [Guide de Soumission Mac App Store](tutorial/mac-app-store-submission-guide.md)
* [Créer une archive](tutorial/application-packaging.md)
* [Utiliser Modules Natifs de Node](tutorial/using-native-node-modules.md)
* [Debugger Processus Principal](tutorial/debugging-main-process.md)
* [Utiliser Selenium et WebDriver](tutorial/using-selenium-and-webdriver.md)
* [Extension DevTools](tutorial/devtools-extension.md)
* [Utiliser le Plugin Pepper Flash](tutorial/using-pepper-flash-plugin.md)
* [Utiliser le Plugin Widevine CDM](tutorial/using-widevine-cdm-plugin.md)
## Tutoriels
* [Démarrage Rapide](tutorial/quick-start.md)
* [Intégration Environnement de Bureau](tutorial/desktop-environment-integration.md)
* [Détection des Evènements En ligne/Hors ligne](tutorial/online-offline-events.md)
## Références API
* [Synopsis](api/synopsis.md)
* [L'objet Process](api/process.md)
* [Commandes Chromes Supportées](api/chrome-command-line-switches.md)
* [Variables d'Environnement](api/environment-variables.md)
### Eléments DOM Personnalisés:
* [Objet `File`](api/file-object.md)
* [Tag `<webview>`](api/web-view-tag.md)
* [Fonction `window.open`](api/window-open.md)
### Modules pour le Processus Principal :
* [app](api/app.md)
* [autoUpdater](api/auto-updater.md)
* [BrowserWindow](api/browser-window.md)
* [contentTracing](api/content-tracing.md)
* [dialog](api/dialog.md)
* [globalShortcut](api/global-shortcut.md)
* [ipcMain](api/ipc-main.md)
* [Menu](api/menu.md)
* [MenuItem](api/menu-item.md)
* [powerMonitor](api/power-monitor.md)
* [powerSaveBlocker](api/power-save-blocker.md)
* [protocol](api/protocol.md)
* [session](api/session.md)
* [webContents](api/web-contents.md)
* [Tray](api/tray.md)
### Modules pour le Processus d'Affichage (Page Web) :
* [desktopCapturer](api/desktop-capturer.md)
* [ipcRenderer](api/ipc-renderer.md)
* [remote](api/remote.md)
* [webFrame](api/web-frame.md)
### Modules pour les deux Processus :
* [clipboard](api/clipboard.md)
* [crashReporter](api/crash-reporter.md)
* [nativeImage](api/native-image.md)
* [screen](api/screen.md)
* [shell](api/shell.md)
## Développement
* [Style de Code](development/coding-style.md)
* [Hiérarchie du Code Source](development/source-code-directory-structure.md)
* [Différences Techniques par rapport à NW.js (anciennement node-webkit)](development/atom-shell-vs-node-webkit.md)
* [Aperçu du Système de Build](development/build-system-overview.md)
* [Instructions de Build (OS X)](development/build-instructions-osx.md)
* [Instructions de Build (Windows)](development/build-instructions-windows.md)
* [Instructions de Build (Linux)](development/build-instructions-linux.md)
* [Installer un Serveur de Symbol dans le debugger](development/setting-up-symbol-server.md)

View file

@ -0,0 +1,129 @@
# Electron FAQ
## Quand est mise à jour la version de Chrome utilisée par Electron ?
La version de Chrome qu'utilise Electron est en général mise à jour une ou deux
semaines après la sortie d'une nouvelle version stable de Chrome.
Etant donné que nous n'utilisons que les versions stables de Chrome, si un fix
important est en beta ou en dev, nous l'intégrerons à la version que nous
utilisons.
## Quand est mise à jour la version de Node.js utilisée par Electron ?
Quand une nouvelle version de Node.js sort, nous attendons en général un mois
avant de mettre à jour celle que nous utilisons dans Electron. Ceci afin
d'éviter les bugs introduits par les nouvelles versions, ce qui arrive très
souvent.
Les nouvelles fonctionnalités de Node.js arrivant la plupart du temps via V8,
et Electron utilisant le V8 du navigateur Chrome, la nouvelle fonctionnalité
JavaScript de la nouvelle version de Node.js est bien souvent déjà dans
Electron.
## La fenêtre/barre d'état de mon application disparait après quelques minutes.
Cela se produit quand la variable qui est utilisée pour stocker la fenêtre/barre
d'état est libérée par le ramasse-miettes.
Nous vous recommandons de lire les articles suivants quand vous rencontrez le
problème :
* [Management de la Mémoire][memory-management] (Anglais)
* [Portée d'une Variable][variable-scope] (Anglais)
Si vous voulez corriger rapidement le problème, vous pouvez rendre les variables
globales en changeant votre code de ça :
```javascript
app.on('ready', function() {
var tray = new Tray('/path/to/icon.png');
})
```
à ça :
```javascript
var tray = null;
app.on('ready', function() {
tray = new Tray('/path/to/icon.png');
})
```
## Je n'arrive pas à utiliser jQuery/RequireJS/Meteor/AngularJS dans Electron.
A cause de l'intégration de Node.js dans Electron, certains mots-clés sont
insérés dans la DOM, comme `module`, `exports`, `require`. Ceci pose des
problèmes pour certaines bibliothèques qui utilisent les mêmes mots-clés.
Pour résoudre ce problème, vous pouvez désactiver l'intégration de node dans
Electron :
```javascript
// Dans le processus principal.
var mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: false
}
});
```
Mais si vous voulez garder la possibilité d'utiliser Node.js et les APIs
Electron, vous devez renommer les mots-clés dans la page avant d'inclure
d'autres bibliothèques :
```html
<head>
<script>
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
<script type="text/javascript" src="jquery.js"></script>
</head>
```
## `require('electron').xxx` is undefined.
Lors de l'utilisation des modules d'Electron, vous pouvez avoir une erreur :
```
> require('electron').webFrame.setZoomFactor(1.0);
Uncaught TypeError: Cannot read property 'setZoomLevel' of undefined
```
Ceci se produit quand vous avez le [module npm `electron`][electron-module]
d'installé, soit en local ou en global, ce qui a pour effet d'écraser les
modules de base d'Electron.
Vous vérifiez que vous utilisez les bons modules, vous pouvez afficher le
chemin du module `electron` :
```javascript
console.log(require.resolve('electron'));
```
et vérifier si il est de la forme :
```
"/path/to/Electron.app/Contents/Resources/atom.asar/renderer/api/lib/exports/electron.js"
```
S'il est de la forme `node_modules/electron/index.js`, vous devez supprimer le
module npm `electron`, ou le renommer.
```bash
npm uninstall electron
npm uninstall -g electron
```
Si vous utilisez le module de base mais que vous continuez d'avoir
l'erreur, ça vient probablement du fait que vous utilisez le module dans le
mauvais processus. Par exemple `electron.app` peut uniquement être utilisé
dans le processus principal, tandis que `electron.webFrame` est uniquement
disponible dans le processus d'affichage.
[memory-management]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management
[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx
[electron-module]: https://www.npmjs.com/package/electron

View file

@ -0,0 +1,101 @@
# Règles de style pour la documentation d'Electron
Choisissez la section appropriée : [lire la documentation d'Electron](#reading-electron-documentation)
ou [écrire de la documentation pour Electron](#writing-electron-documentation).
## Ecrire de la documentation pour Electron
La documentation d'Electron a été écrite en suivant les règles ci-dessous :
- Maximum un titre `h1` par page.
- Utilisation de `bash` au lieu de `cmd` dans les blocs de code (à cause de la
coloration syntaxique).
- Les titres `h1` devraient reprendre le nom de l'objet (i.e. `browser-window`
`BrowserWindow`).
- Cependant, les traits d'union sont acceptés pour les noms de fichier.
- Pas de titre directement après un autre, ajoutez au minimum une ligne de
description entre les deux.
- Les entêtes des méthodes sont entre accents graves (backquotes) `code`.
- Les entêtes des évènements sont entre des apostrophes 'quotation'.
- Les listes ne doivent pas dépasser 2 niveaux (à cause du formattage du
markdown).
- Ajouter des titres de section: Evènements, Méthodes de classe, et Méthodes
d'instance.
- Utiliser 'will' au lieu de 'would' lors de la description du retour.
- Les évènements et méthodes sont des titres `h3`.
- Les arguments optionnels sont notés `function (required[, optional])`.
- Les arguments optionnels sont indiqués quand appelés dans la liste.
- La longueur des lignes ne dépasse pas 80 caractères.
- Les méthodes spécifiques à une plateforme sont notées en italique.
- ```### `method(foo, bar)` _OS X_```
- Préférer 'in the ___ process' au lieu de 'on'
### Traductions de la Documentation
Les traductions de la documentation d'Electron sont dans le dossier
`docs-translations`.
Pour ajouter une nouvelle langue (ou commencer) :
- Créer un sous-dossier avec comme nom le code langage.
- A l'intérieur de ce dossier, dupliquer le dossier `docs`, en gardant le même
nom de dossiers et de fichiers.
- Traduire les fichiers.
- Mettre à jour le `README.md` à l'intérieur du dossier de langue en mettant les
liens vers les fichiers traduits.
- Ajouter un lien vers le nouveau dossier de langue dans le [README](https://github.com/atom/electron#documentation-translations)
principal d'Electron.
## Lire la documentation d'Electron
Quelques indications pour comprendre la syntaxe de la documentation d'Electron.
### Méthodes
Un exemple de la documentation d'une [méthode](https://developer.mozilla.org/en-US/docs/Glossary/Method)
(Anglais)
---
`methodName(required[, optional]))`
* `require` String (**required**)
* `optional` Integer
---
Le nom de la méthode est suivi des arguments de celle-ci. Les arguments
optionnels sont notés entre crochets, avec une virgule si ceux-ci suivent un
autre argument.
En-dessous de la méthode, chaque argument est détaillé avec son type.
Celui-ci peut être un type générique :
[`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String),
[`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number),
[`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object),
[`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
ou un type personnalisé comme le [`webContent`](api/web-content.md) d'Electron.
### Evènements
Un exemple d'une documentation d'un [évènement](https://developer.mozilla.org/en-US/docs/Web/API/Event)
(Anglais)
---
Event: 'wake-up'
Returns:
* `time` String
---
L'évènement est une chaine utilisée après un listener `.on`. Si il retourne une
valeur, elle est écrite en dessous ainsi que son type. Si vous voulez écouter et
répondre à l'évènement wake-up, ça donne quelque chose comme :
```javascript
Alarm.on('wake-up', function(time) {
console.log(time)
})
```

View file

@ -52,7 +52,7 @@
* `channel` String - イベント名
* `arg` (optional)
`channel`経由でメインプロセスに同期にイベントを送信し、任意の引数を送信できます。
`channel`経由でメインプロセスに同期にイベントを送信し、任意の引数を送信できます。
メインプロセスは`ipcMain`で`channel`を受信することでハンドルし、 `event.returnValue`を設定してリプライします。

View file

@ -12,6 +12,27 @@ Node.js の新しいバージョンがリリースされたとき、私たちは
通常、Node.js の新しい機能は V8 のアップグレードによってもたらされますが、Electron は Chrome ブラウザーに搭載されている V8 を使用しているので、新しい Node.js に入ったばかりのピカピカに新しい JavaScript 機能は Electron ではたいてい既に導入されています。
## ウェブページ間のデータを共有する方法は?
ウェブページレンダラープロセス間のデータを共有するために最も単純な方法は、ブラウザで、すでに提供されているHTML5 APIを使用することです。もっとも良い方法は、[Storage API][storage]、[`localStorage`][local-storage]、[`sessionStorage`][session-storage]、[IndexedDB][indexed-db]です。
```javascript
// In the main process.
global.sharedObject = {
someProperty: 'default value'
};
```
```javascript
// In page 1.
require('remote').getGlobal('sharedObject').someProperty = 'new value';
```
```javascript
// In page 2.
console.log(require('remote').getGlobal('sharedObject').someProperty);
```
## 何分か経つと、アプリの Window/tray が消えてしまいます
これは、Window/trayを格納するのに使用している変数がガベージコレクトされたときに発生します。
@ -104,3 +125,7 @@ npm uninstall -g electron
[memory-management]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management
[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx
[electron-module]: https://www.npmjs.com/package/electron
[storage]: https://developer.mozilla.org/en-US/docs/Web/API/Storage
[local-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
[session-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
[indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API

View file

@ -210,6 +210,23 @@ var window = new BrowserWindow({...});
window.setProgressBar(0.5);
```
## タスクバーでアイコンをオーバーレイする (Windows)
Windowsで、タスクバーボタンはアプリケーションステータスを表示するために小さなオーバーレイを使うことができます。MSDNから引用します。
> アイコン オーバーレイは、状況に応じた状態通知として機能し、通知領域に状態アイコンを個別に表示する必要性をなくして、情報をユーザーに伝えることを目的としています。たとえば、現在、通知領域に表示される Microsoft Office Outlook の新着メールの通知は、タスク バー ボタンのオーバーレイとして表示できるようになります。ここでも、開発サイクルの間に、アプリケーションに最適な方法を決定する必要があります。アイコン オーバーレイは、重要で長期にわたる状態や通知 (ネットワークの状態、メッセンジャーの状態、新着メールなど) を提供することを目的としています。ユーザーに対して、絶えず変化するオーバーレイやアニメーションを表示しないようにしてください。
__タスクバーボタンでのオーバーレイ:__
![Overlay on taskbar button](https://i-msdn.sec.s-msft.com/dynimg/IC420441.png)
ウィンドウでオーバーレイアイコンを設定するために、[BrowserWindow.setOverlayIcon][setoverlayicon] APIを使用できます。
```javascript
var window = new BrowserWindow({...});
window.setOverlayIcon('path/to/overlay.png', 'Description for overlay');
```
## Windowのファイル表示 (OS X)
OS Xでは、ウィンドウがrepresented fileを設定でき、タイトルバー上にファイルのアイコンを表示でき、タイトル上でCommand-クリックまたはControl-クリックをすると、パスがポップアップ表示されます。
@ -228,15 +245,16 @@ window.setRepresentedFilename('/etc/passwd');
window.setDocumentEdited(true);
```
[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath
[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments
[setusertaskstasks]: ../api/app.md#appsetusertaskstasks
[setprogressbar]: ../api/browser-window.md#browserwindowsetprogressbarprogress
[setrepresentedfilename]: ../api/browser-window.md#browserwindowsetrepresentedfilenamefilename
[setdocumentedited]: ../api/browser-window.md#browserwindowsetdocumenteditededited
[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-os-x-windows
[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments-os-x-windows
[setusertaskstasks]: ../api/app.md#appsetusertaskstasks-windows
[setprogressbar]: ../api/browser-window.md#winsetprogressbarprogress
[setoverlayicon]: ../api/browser-window.md#winsetoverlayiconoverlay-description-windows-7
[setrepresentedfilename]: ../api/browser-window.md#winsetrepresentedfilenamefilename-os-x
[setdocumentedited]: ../api/browser-window.md#winsetdocumenteditededited-os-x
[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx
[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher
[setthumbarbuttons]: ../api/browser-window.md#browserwindowsetthumbarbuttonsbuttons
[setthumbarbuttons]: ../api/browser-window.md#winsetthumbarbuttonsbuttons-windows-7
[tray-balloon]: ../api/tray.md#traydisplayballoonoptions-windows
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx
[notification-spec]: https://developer.gnome.org/notification-spec/

View file

@ -24,6 +24,8 @@ Electron はウェブページを表示させるために Chromium を使用し
Electron では、メインプロセスとレンダラープロセスとのコミュニケーションをするために [ipc](../api/ipc-renderer.md) モジュールを提供しています。またそれと、RPC 形式の通信を行う [remote](../api/remote.md) モジュールもあります。
Electron では、メインプロセスとレンダラープロセスとのコミュニケーションをするには幾つかのほうほうがあります。メッセージを送信する[`ipcRenderer`](../api/ipc-renderer.md)モジュールと[`ipcMain`](../api/ipc-main.md)モジュールのように、RPC 形式の通信を行う[remote](../api/remote.md)モジュールです。[ウェブページ間のデータを共有する方法][share-data]にFAQエントリーがあります。
## Electronアプリを作成する
一般的に Electron アプリの構成は次のようになります:
@ -169,3 +171,5 @@ $ cd electron-quick-start
# Install dependencies and run the app
$ npm install && npm start
```
[share-data]: ../faq/electron-faq.md#how-to-share-data-between-web-pages

View file

@ -41,7 +41,7 @@ var driver = new webdriver.Builder()
.withCapabilities({
chromeOptions: {
// Here is the path to your Electron binary.
binary: '/Path-to-Your-App.app/Contents/MacOS/Atom',
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron',
}
})
.forBrowser('electron')

View file

@ -6,6 +6,8 @@ Electronで、Chromeブラウザーに同梱される Widevine CDMプラグイ
Electronは、ライセンス的な理由でWidevine CDMプラグインは同梱されません。Widevine CDMプラグインを取得するために、最初に、使用するElectronビルドのChromバージョンとアーキテクチャを合わせた公式のChromeブラウザーをインストールする必要があります。
__Note:__ Chromeブラウザの主要バージョンは、Electronが使用するChromeバージョンと同じでなければなりません。そうでなければ、プラグインは、`navigator.plugins`経由でロードされて表示されるにも関わらず動作しません。
### Windows & OS X
Chromeブラウザーで、`chrome://components/`を開き、 `WidevineCdm` を探し、それが最新であることを確認し、`APP_DATA/Google/Chrome/WidevineCDM/VERSION/_platform_specific/PLATFORM_ARCH/`ディレクトリからすべてのプラグインバイナリを探します。

View file

@ -92,7 +92,7 @@ Returns:
이 이벤트를 처리할 땐 반드시 `event.preventDefault()`를 호출해야 합니다.
Windows에선 `process.argv`를 통해 파일 경로를 얻을 수 있습니다.
Windows에선 `process.argv` (메인 프로세스에서)를 통해 파일 경로를 얻을 수 있습니다.
### Event: 'open-url' _OS X_
@ -164,7 +164,7 @@ Returns:
기본 동작을 방지하고 인증을 승인할 수 있습니다.
```javascript
session.on('certificate-error', function(event, webContents, url, error, certificate, callback) {
app.on('certificate-error', function(event, webContents, url, error, certificate, callback) {
if (url == "https://github.com") {
// Verification logic.
event.preventDefault();
@ -523,7 +523,7 @@ dock 아이콘을 표시합니다.
### `app.dock.setMenu(menu)` _OS X_
* `menu` Menu
* `menu` [Menu](menu.md)
어플리케이션의 [dock menu][dock-menu]를 설정합니다.

View file

@ -451,7 +451,6 @@ var win = new BrowserWindow({ width: 800, height: 600 });
* `aspectRatio` 유지하려 하는 컨텐츠 뷰 일부의 종횡비
* `extraSize` Object (optional) - 종횡비를 유지하는 동안 포함되지 않을 엑스트라 크기.
사용 가능한 속성:
* `width` Integer
* `height` Integer
@ -469,7 +468,7 @@ var win = new BrowserWindow({ width: 800, height: 600 });
### `win.setBounds(options[, animate])`
* `options` Object, properties:
* `options` Object
* `x` Integer
* `y` Integer
@ -719,8 +718,7 @@ Windows 메시지 훅을 등록합니다. `callback`은 WndProc에서 메시지
### `win.capturePage([rect, ]callback)`
* `rect` Object (optional) - 캡쳐할 페이지의 영역.
사용할 수 있는 속성은 다음과 같습니다:
* `rect` Object (optional) - 캡쳐할 페이지의 영역
* `x` Integer
* `y` Integer
* `width` Integer
@ -773,7 +771,7 @@ Linux 플랫폼에선 Unity 데스크톱 환경만 지원합니다. 그리고
아이콘입니다. `null`로 지정하면 빈 오버레이가 사용됩니다
* `description` String - 접근성 설정에 의한 스크린 리더에 제공될 설명입니다
현재 작업표시줄 아이콘에 16px 크기의 오버레이를 지정합니다. 보통 이 기능은
현재 작업표시줄 아이콘에 16 x 16 픽셀 크기의 오버레이를 지정합니다. 보통 이 기능은
어플리케이션의 여러 상태를 사용자에게 소극적으로 알리기 위한 방법으로 사용됩니다.
### `win.setHasShadow(hasShadow)` _OS X_
@ -790,34 +788,34 @@ Linux 플랫폼에선 Unity 데스크톱 환경만 지원합니다. 그리고
### `win.setThumbarButtons(buttons)` _Windows 7+_
`buttons` - `button` 객체의 배열
`button` 객체는 다음과 같은 속성을 가지고 있습니다:
* `icon` [NativeImage](native-image.md) - 미리보기 툴바에 보여질 아이콘.
* `tooltip` String (optional) - 버튼의 툴팁 텍스트.
* `flags` Array (optional) - 버튼의 특정 동작 및 상태 제어. 기본적으로 `enabled`
사용됩니다. 이 속성은 다음 문자열들을 포함할 수 있습니다:
* `enabled` - 사용자가 사용할 수 있도록 버튼이 활성화 됩니다.
* `disabled` - 버튼이 비활성화 됩니다. 버튼은 표시되지만 시각적인 상태는 사용자의
동작에 응답하지 않는 비활성화 상태로 표시됩니다.
* `dismissonclick` - 버튼이 클릭되면 작업표시줄 버튼의 미리보기(flyout)가 즉시
종료됩니다.
* `nobackground` - 버튼의 테두리를 표시하지 않습니다. 이미지에만 사용할 수 있습니다.
* `hidden` - 버튼을 사용자에게 표시되지 않도록 숨깁니다.
* `noninteractive` - 버튼은 활성화되어 있지만 반응이 제거되며 버튼을 눌러도
눌려지지 않은 상태를 유지합니다. 이 값은 버튼을 알림의 용도로 사용하기 위해
만들어졌습니다.
* `click` - Function
* `buttons` - Array
윈도우 작업표시줄 버튼 레이아웃의 미리보기 이미지 영역에 미리보기 툴바와 버튼 세트를
지정합니다. 반환되는 `Boolean` 값은 미리보기 툴바가 성공적으로 추가됬는지를 알려줍니다.
추가합니다. 반환되는 `Boolean` 값은 미리보기 툴바가 성공적으로 추가됬는지를 알려줍니다.
미리보기 이미지 영역의 제한된 크기로 인해 미리보기 툴바에 추가될 수 있는 최대 버튼의
개수는 7개이며 이 이상 추가될 수 없습니다. 플랫폼의 제약으로 인해 미리보기 툴바는 한 번
설정되면 삭제할 수 없습니다. 하지만 이 API에 빈 배열을 전달하여 버튼들을 제거할 수
있습니다.
`buttons``Button` 객체의 배열입니다:
* `Button` 객체
* `icon` [NativeImage](native-image.md) - 미리보기 툴바에 보여질 아이콘.
* `tooltip` String (optional) - 버튼의 툴팁 텍스트.
* `flags` Array (optional) - 버튼의 특정 동작 및 상태 제어. 기본적으로 `enabled`
사용됩니다. 이 속성은 다음 문자열들을 포함할 수 있습니다:
* `enabled` - 사용자가 사용할 수 있도록 버튼이 활성화 됩니다.
* `disabled` - 버튼이 비활성화 됩니다. 버튼은 표시되지만 시각적인 상태는 사용자의
동작에 응답하지 않는 비활성화 상태로 표시됩니다.
* `dismissonclick` - 버튼이 클릭되면 작업표시줄 버튼의 미리보기(flyout)가 즉시
종료됩니다.
* `nobackground` - 버튼의 테두리를 표시하지 않습니다. 이미지에만 사용할 수 있습니다.
* `hidden` - 버튼을 사용자에게 표시되지 않도록 숨깁니다.
* `noninteractive` - 버튼은 활성화되어 있지만 반응이 제거되며 버튼을 눌러도
눌려지지 않은 상태를 유지합니다. 이 값은 버튼을 알림의 용도로 사용하기 위해
만들어졌습니다.
### `win.showDefinitionForSelection()` _OS X_
페이지의 선택된 단어에 대한 사전 검색 결과 팝업을 표시합니다.

View file

@ -62,6 +62,19 @@ console.log(clipboard.readText('selection'));
클립보드에 `image`를 씁니다.
### `clipboard.readRtf([type])`
* `type` String (optional)
클립보드로부터 RTF 형식으로 컨텐츠를 읽어옵니다.
### `clipboard.writeRtf(text[, type])`
* `text` String
* `type` String (optional)
클립보드에 `text`를 RTF 형식으로 씁니다.
### `clipboard.clear([type])`
* `type` String (optional)

View file

@ -22,19 +22,15 @@ crashReporter.start({
### `crashReporter.start(options)`
* `options` Object, properties:
* `productName` String, 기본값: Electron
* `companyName` String (**필수항목**)
* `submitURL` String, (**필수항목**)
* 크래시 리포트는 POST 방식으로 이 URL로 전송됩니다.
* `autoSubmit` Boolean, 기본값: true
* true로 지정할 경우 유저의 승인 없이 자동으로 오류를 보고합니다.
* `ignoreSystemCrashHandler` Boolean, 기본값: false
* `extra` Object
* 크래시 리포트 시 같이 보낼 추가 정보를 지정하는 객체입니다.
* 문자열로 된 속성만 정상적으로 보내집니다.
* 중첩 객체는 지원되지 않습니다. (Nested objects are not supported)
* `options` Object
* `companyName` String
* `submitURL` String - 크래시 리포트는 POST 방식으로 이 URL로 전송됩니다.
* `productName` String (optional) - 기본값은 `Electron` 입니다.
* `autoSubmit` Boolean - 유저의 승인 없이 자동으로 오류를 보고합니다. 기본값은
`true` 입니다.
* `ignoreSystemCrashHandler` Boolean - 기본값은 `false` 입니다.
* `extra` Object - 크래시 리포트 시 같이 보낼 추가 정보를 지정하는 객체입니다.
문자열로 된 속성만 정상적으로 보내집니다. 중첩된 객체는 지원되지 않습니다.
다른 crashReporter API를 사용하기 전에 이 메서드를 먼저 호출해야 합니다.

View file

@ -8,8 +8,7 @@
## 메시지 전송
물론 메시지를 받는 것 말고도 메인 프로세스에서 랜더러 프로세스로 보내는 것도 가능합니다.
자세한 내용은 [webContents.send](web-contents.md#webcontentssendchannel-arg1-arg2-)를
참고하세요.
자세한 내용은 [webContents.send][web-contents-send]를 참고하세요.
* 메시지를 전송할 때 이벤트 이름은 `channel`이 됩니다.
* 메시지에 동기로 응답할 땐 반드시 `event.returnValue`를 설정해야 합니다.
@ -46,34 +45,40 @@ ipcRenderer.send('asynchronous-message', 'ping');
`ipcMain`은 다음과 같은 이벤트 리스닝 메서드를 가지고 있습니다:
### `ipcMain.on(channel, callback)`
### `ipcMain.on(channel, listener)`
* `channel` String - 이벤트 이름
* `callback` Function
* `channel` String
* `listener` Function
이벤트가 발생하면 `event` 객체와 임의 메시지와 함께 `callback`이 호출됩니다.
`channel`에 대해 이벤트를 리스닝합니다. 새로운 메시지가 도착하면 `listener`
`listener(event, args...)` 형식으로 호출됩니다.
### `ipcMain.removeListener(channel, callback)`
### `ipcMain.once(channel, listener)`
* `channel` String - 이벤트의 이름
* `callback` Function - `ipcMain.on(channel, callback)`에서 사용한 함수의 레퍼런스
* `channel` String
* `listener` Function
이벤트에 대해 한 번만 작동하는 `listener` 함수를 등록합니다. 이 `listener`는 등록된
`channel`에 보내지는 메시지에 한해 호출됩니다. 호출된 이후엔 리스너가 삭제됩니다.
### `ipcMain.removeListener(channel, listener)`
* `channel` String
* `listener` Function
메시지 수신을 완료한 후, 더 이상의 콜백이 필요하지 않을 때 또는 몇 가지 이유로 채널의
메시지 전송을 멈출수 없을 때, 이 함수를 통해 지정한 채널에 대한 콜백을 삭제할 수
있습니다.
지정한 `channel`에 대한 리스너를 저장하는 배열에서 지정한 `listener`를 삭제합니다.
### `ipcMain.removeAllListeners(channel)`
* `channel` String - 이벤트의 이름
* `channel` String (optional)
이 ipc 채널에 등록된 *모든* 핸들러들을 삭제합니다.
이 ipc 채널에 등록된 모든 핸들러들을 삭제하거나 지정한 `channel`을 삭제합니다.
### `ipcMain.once(channel, callback)`
`ipcMain.on()` 대신 이 함수를 사용할 경우 핸들러가 단 한 번만 호출됩니다.
`callback`이 한 번 호출된 이후 활성화되지 않습니다.
## IPC Event
## Event 객체
`callback`에서 전달된 `event` 객체는 다음과 같은 메서드와 속성을 가지고 있습니다:
@ -85,5 +90,6 @@ ipcRenderer.send('asynchronous-message', 'ping');
메시지를 보낸 `webContents` 객체를 반환합니다. `event.sender.send` 메서드를 통해
비동기로 메시지를 전달할 수 있습니다. 자세한 내용은
[webContents.send](web-contents.md#webcontentssendchannel-arg1-arg2-)를
참고하세요.
[webContents.send][web-contents-send]를 참고하세요.
[web-contents-send]: web-contents.md#webcontentssendchannel-arg1-arg2-

View file

@ -10,32 +10,38 @@
`ipcRenderer`는 다음과 같은 이벤트 리스닝 메서드를 가지고 있습니다:
### `ipcRenderer.on(channel, callback)`
### `ipcMain.on(channel, listener)`
* `channel` String - 이벤트 이름
* `callback` Function
* `channel` String
* `listener` Function
이벤트가 일어나면 `event` 객체와 임의의 인자와 함께 `callback` 함수가 호출됩니다.
`channel`에 대해 이벤트를 리스닝합니다. 새로운 메시지가 도착하면 `listener`
`listener(event, args...)` 형식으로 호출됩니다.
### `ipcMain.removeListener(channel, callback)`
### `ipcMain.once(channel, listener)`
* `channel` String - 이벤트의 이름
* `callback` Function - `ipcMain.on(channel, callback)`에서 사용한 함수의 레퍼런스
* `channel` String
* `listener` Function
이벤트에 대해 한 번만 작동하는 `listener` 함수를 등록합니다. 이 `listener`는 등록된
`channel`에 보내지는 메시지에 한해 호출됩니다. 호출된 이후엔 리스너가 삭제됩니다.
### `ipcMain.removeListener(channel, listener)`
* `channel` String
* `listener` Function
메시지 수신을 완료한 후, 더 이상의 콜백이 필요하지 않을 때 또는 몇 가지 이유로 채널의
메시지 전송을 멈출수 없을 때, 이 함수를 통해 지정한 채널에 대한 콜백을 삭제할 수
있습니다.
지정한 `channel`에 대한 리스너를 저장하는 배열에서 지정한 `listener`를 삭제합니다.
### `ipcMain.removeAllListeners(channel)`
* `channel` String - 이벤트의 이름
* `channel` String (optional)
이 ipc 채널에 등록된 *모든* 핸들러들을 삭제합니다.
### `ipcMain.once(channel, callback)`
`ipcMain.on()` 대신 이 함수를 사용할 경우 핸들러가 단 한 번만 호출됩니다.
`callback`이 한 번 호출된 이후 활성화되지 않습니다.
이 ipc 채널에 등록된 모든 핸들러들을 삭제하거나 지정한 `channel`을 삭제합니다.
## 메시지 보내기
@ -43,23 +49,26 @@
### `ipcRenderer.send(channel[, arg1][, arg2][, ...])`
* `channel` String - 이벤트 이름
* `channel` String
* `arg` (optional)
`channel`을 통해 메인 프로세스에 비동기 메시지를 보냅니다. 그리고 필요에 따라 임의의
인자를 사용할 수도 있습니다. 메인 프로세스는 `ipcMain` 모듈의 `channel` 이벤트를 통해
인수를 사용할 수도 있습니다. 인수들은 내부적으로 JSON 포맷으로 직렬화 되며, 이후 함수와
프로토타입 체인은 포함되지 않게 됩니다.
메인 프로세스는 `ipcMain` 모듈의 `channel` 이벤트를 통해
이벤트를 리스닝 할 수 있습니다.
### `ipcRenderer.sendSync(channel[, arg1][, arg2][, ...])`
* `channel` String - 이벤트 이름
* `channel` String
* `arg` (optional)
`channel`을 통해 메인 프로세스에 동기 메시지를 보냅니다. 그리고 필요에 따라 임의의
인자를 사용할 수도 있습니다. 메인 프로세스는 `ipc`를 통해 `channel` 이벤트를 리스닝
할 수 있습니다.
인자를 사용할 수도 있습니다. 인수들은 내부적으로 JSON 포맷으로 직렬화 되며, 이후 함수와
프로토타입 체인은 포함되지 않게 됩니다.
메인 프로세스에선 `ipcMain` 모듈의 `channel` 이벤트를 통해 받은
메인 프로세스`ipcMain` 모듈을 통해 `channel` 이벤트를 리스닝 할 수 있고,
`event.returnValue`로 회신 할 수 있습니다.
__참고:__ 동기 메서드는 모든 랜더러 프로세스의 작업을 일시 중단시킵니다. 사용 목적이
@ -67,7 +76,7 @@ __참고:__ 동기 메서드는 모든 랜더러 프로세스의 작업을 일
### `ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])`
* `channel` String - 이벤트 이름
* `channel` String
* `arg` (optional)
`ipcRenderer.send`와 비슷하지만 이벤트를 메인 프로세스 대신 호스트 페이지내의

View file

@ -59,7 +59,8 @@ var ses = session.fromPartition('persist:name');
Electron의 `webContents`에서 `item`을 다운로드할 때 발생하는 이벤트입니다.
`event.preventDefault()` 메서드를 호출하면 다운로드를 취소합니다.
`event.preventDefault()` 메서드를 호출하면 다운로드를 취소하고, 프로세스의 다음
틱부터 `item`을 사용할 수 없게 됩니다.
```javascript
session.defaultSession.on('will-download', function(event, item, webContents) {
@ -293,26 +294,32 @@ myWindow.webContents.session.setCertificateVerifyProc(function(hostname, cert, c
* `handler` Function
* `webContents` Object - [WebContents](web-contents.md) 권한을 요청.
* `permission` String - 'media', 'geolocation', 'notifications',
'midiSysex'의 나열.
'midiSysex', 'pointerLock', 'fullscreen'의 나열.
* `callback` Function - 권한 허용 및 거부.
`session`의 권한 요청에 응답을 하는데 사용하는 핸들러를 설정합니다.
`callback('granted')`를 호출하면 권한 제공을 허용하고 `callback('denied')`를
`callback(true)`를 호출하면 권한 제공을 허용하고 `callback(false)`를
호출하면 권한 제공을 거부합니다.
```javascript
session.fromPartition(partition).setPermissionRequestHandler(function(webContents, permission, callback) {
if (webContents.getURL() === host) {
if (permission == "notifications") {
callback(); // 거부됨.
callback(false); // 거부됨.
return;
}
}
callback('granted');
callback(true);
});
```
#### `ses.clearHostResolverCache([callback])`
* `callback` Function (optional) - 작업이 완료되면 호출됩니다.
호스트 리소버(resolver) 캐시를 지웁니다.
#### `ses.webRequest`
`webRequest` API는 생명주기의 다양한 단계에 맞춰 요청 컨텐츠를 가로채거나 변경할 수

View file

@ -25,12 +25,16 @@ shell.openExternal('https://github.com');
지정한 파일을 데스크톱 기본 프로그램으로 엽니다.
### `shell.openExternal(url)`
### `shell.openExternal(url[, options])`
* `url` String
* `options` Object (optional) _OS X_
* `activate` Boolean - `true`로 설정하면 어플리케이션을 바로 활성화 상태로
실행합니다. 기본값은 `true`입니다.
제공된 외부 프로토콜 URL을 기반으로 데스크톱의 기본 프로그램으로 엽니다. (예를 들어
mailto: URL은 유저의 기본 이메일 에이전트로 URL을 엽니다.)
mailto: URL은 유저의 기본 이메일 에이전트로 URL을 엽니다.) 어플리케이션이 해당 URL을
열 수 있을 때 `true`를 반환합니다. 아니라면 `false`를 반환합니다.
역주: 폴더는 'file:\\\\C:\\'와 같이 지정하여 열 수 있습니다. (Windows의 경우)

View file

@ -32,6 +32,13 @@ __플랫폼별 한계:__
트레이 아이콘이 작동하도록 만들 수 있습니다.
* 앱 알림 표시기는 컨텍스트 메뉴를 가지고 있을 때만 보입니다.
* Linux에서 앱 표시기가 사용될 경우, `click` 이벤트는 무시됩니다.
* Linux에서 각각 개별 `MenuItem`의 변경을 적용하려면 `setContextMenu`를 다시
호출해야 합니다. 예를 들면:
```javascript
contextMenu.items[2].checked = false;
appIcon.setContextMenu(contextMenu);
```
이러한 이유로 Tray API가 모든 플랫폼에서 똑같이 작동하게 하고 싶다면 `click` 이벤트에
의존해선 안되며 언제나 컨텍스트 메뉴를 포함해야 합니다.

View file

@ -255,8 +255,8 @@ Returns:
* `result` Object
* `requestId` Integer
* `finalUpdate` Boolean - 더 많은 응답이 따르는 경우를 표시합니다.
* `matches` Integer (Optional) - 일치하는 개수.
* `selectionArea` Object (Optional) - 첫 일치 부위의 좌표.
* `matches` Integer (optional) - 일치하는 개수.
* `selectionArea` Object (optional) - 첫 일치 부위의 좌표.
[`webContents.findInPage`](web-contents.md#webcontentsfindinpage) 요청의 결과를
사용할 수 있을 때 발생하는 이벤트입니다.
@ -307,7 +307,7 @@ Returns:
### `webContents.loadURL(url[, options])`
* `url` URL
* `options` Object (optional), 속성들:
* `options` Object (optional)
* `httpReferrer` String - HTTP 레퍼러 url.
* `userAgent` String - 요청을 시작한 유저 에이전트.
* `extraHeaders` String - "\n"로 구분된 Extra 헤더들.
@ -493,7 +493,7 @@ CSS 코드를 현재 웹 페이지에 삽입합니다.
### `webContents.findInPage(text[, options])`
* `text` String - 찾을 컨텐츠, 반드시 공백이 아니여야 합니다.
* `options` Object (Optional)
* `options` Object (optional)
* `forward` Boolean - 앞에서부터 검색할지 뒤에서부터 검색할지 여부입니다. 기본값은
`true`입니다.
* `findNext` Boolean - 작업을 계속 처리할지 첫 요청만 처리할지 여부입니다. 기본값은
@ -546,11 +546,10 @@ ServiceWorker가 존재하면 모두 등록을 해제하고 JS Promise가 만족
### `webContents.print([options])`
`options` Object (optional), properties:
* `silent` Boolean - 사용자에게 프린트 설정을 묻지 않습니다. 기본값을 `false`입니다.
* `printBackground` Boolean - 웹 페이지의 배경 색과 이미지를 출력합니다. 기본값은
`false`입니다.
`options` Object (optional)
* `silent` Boolean - 사용자에게 프린트 설정을 묻지 않습니다. 기본값을 `false`입니다.
* `printBackground` Boolean - 웹 페이지의 배경 색과 이미지를 출력합니다. 기본값은
`false`입니다.
윈도우의 웹 페이지를 프린트합니다. `silent``false`로 지정되어있을 땐, Electron이
시스템의 기본 프린터와 기본 프린터 설정을 가져옵니다.
@ -565,32 +564,23 @@ print기능을 사용하지 않는 경우 전체 바이너리 크기를 줄이
### `webContents.printToPDF(options, callback)`
`options` Object, properties:
* `marginsType` Integer - 사용할 마진의 종류를 지정합니다.
* 0 - default
* 1 - none
* 2 - minimum
* `pageSize` String - 생성되는 PDF의 페이지 크기를 지정합니다.
* `A5`
* `A4`
* `A3`
* `Legal`
* `Letter`
* `Tabloid`
* `printBackground` Boolean - CSS 배경을 프린트할지 여부를 정합니다.
* `printSelectionOnly` Boolean - 선택된 영역만 프린트할지 여부를 정합니다.
* `landscape` Boolean - landscape을 위해선 `true`를, portrait를 위해선 `false`
사용합니다.
`callback` Function - `function(error, data) {}`
* `error` Error
* `data` Buffer - PDF 파일 내용.
* `options` Object
* `marginsType` Integer - 사용할 마진의 종류를 지정합니다. 0 부터 2 사이 값을 사용할
수 있고 각각 기본 마진, 마진 없음, 최소 마진입니다.
* `pageSize` String - 생성되는 PDF의 페이지 크기를 지정합니다. 값은 `A3`, `A4`,
`A5`, `Legal`, `Letter``Tabloid`가 사용될 수 있습니다.
* `printBackground` Boolean - CSS 배경을 프린트할지 여부를 정합니다.
* `printSelectionOnly` Boolean - 선택된 영역만 프린트할지 여부를 정합니다.
* `landscape` Boolean - landscape을 위해선 `true`를, portrait를 위해선 `false`
사용합니다.
* `callback` Function - `function(error, data) {}`
Chromium의 미리보기 프린팅 커스텀 설정을 이용하여 윈도우의 웹 페이지를 PDF로
프린트합니다.
`callback`은 작업이 완료되면 `callback(error, data)` 형식으로 호출됩니다. `data`
생성된 PDF 데이터를 담고있는 `Buffer`입니다.
기본으로 비어있는 `options`은 다음과 같이 여겨지게 됩니다:
```javascript
@ -643,7 +633,7 @@ mainWindow.webContents.on('devtools-opened', function() {
### `webContents.openDevTools([options])`
* `options` Object (optional). Properties:
* `options` Object (optional)
* `detach` Boolean - 새 창에서 개발자 도구를 엽니다.
개발자 도구를 엽니다.
@ -681,8 +671,11 @@ mainWindow.webContents.on('devtools-opened', function() {
* `arg` (optional)
`channel`을 통하여 렌더러 프로세스에 비동기 메시지를 보냅니다. 임의의 인수를 보낼수도
있습니다. 렌더러 프로세스는 `ipcRenderer` 모듈을 통하여 `channel`를 리슨하여 메시지를
처리할 수 있습니다.
있습니다. 인수들은 내부적으로 JSON 포맷으로 직렬화 되며, 이후 함수와 프로토타입 체인은
포함되지 않게 됩니다.
렌더러 프로세스는 `ipcRenderer` 모듈을 통하여 `channel`를 리스닝하여 메시지를 처리할
수 있습니다.
메인 프로세스에서 렌더러 프로세스로 메시지를 보내는 예시 입니다:

View file

@ -178,7 +178,7 @@ webview.addEventListener("dom-ready", function() {
### `<webview>.loadURL(url[, options])`
* `url` URL
* `options` Object (optional), 속성들:
* `options` Object (optional)
* `httpReferrer` String - HTTP 레퍼러 url.
* `userAgent` String - 요청을 시작한 유저 에이전트.
* `extraHeaders` String - "\n"로 구분된 Extra 헤더들.
@ -370,7 +370,7 @@ Service worker에 대한 개발자 도구를 엽니다.
### `webContents.findInPage(text[, options])`
* `text` String - 찾을 컨텐츠, 반드시 공백이 아니여야 합니다.
* `options` Object (Optional)
* `options` Object (optional)
* `forward` Boolean - 앞에서부터 검색할지 뒤에서부터 검색할지 여부입니다. 기본값은
`true`입니다.
* `findNext` Boolean - 작업을 계속 처리할지 첫 요청만 처리할지 여부입니다. 기본값은
@ -557,8 +557,8 @@ Returns:
* `result` Object
* `requestId` Integer
* `finalUpdate` Boolean - 더 많은 응답이 따르는 경우를 표시합니다.
* `matches` Integer (Optional) - 일치하는 개수.
* `selectionArea` Object (Optional) - 첫 일치 부위의 좌표.
* `matches` Integer (optional) - 일치하는 개수.
* `selectionArea` Object (optional) - 첫 일치 부위의 좌표.
[`webContents.findInPage`](web-contents.md#webcontentsfindinpage) 요청의 결과를
사용할 수 있을 때 발생하는 이벤트입니다.

View file

@ -18,6 +18,34 @@ Node.js의 새로운 기능은 보통 V8 업그레이드에서 가져옵니다.
브라우저에 탑재된 V8을 사용하고 있습니다. 눈부신 새로운 Node.js 버전의 자바스크립트
기능은 보통 이미 Electron에 있습니다.
## 어떻게 웹 페이지 간에 데이터를 공유할 수 있나요?
두 웹페이지 간에 (랜더러 프로세스) 데이터를 공유하려면 간단히 이미 모든 브라우저에서
사용할 수 있는 HTML5 API들을 사용하면 됩니다. 가장 좋은 후보는
[Storage API][storage], [`localStorage`][local-storage],
[`sessionStorage`][session-storage], 그리고 [IndexedDB][indexed-db]가 있습니다.
또는 Electron에서만 사용할 수 있는 IPC 시스템을 사용하여 메인 프로세스의 global
변수에 데이터를 저장한 후 다음과 같이 랜더러 프로세스에서 `remote` 모듈을 사용하여
접근할 수 있습니다:
```javascript
// 메인 프로세스에서
global.sharedObject = {
someProperty: 'default value'
};
```
```javascript
// 첫 번째 페이지에서
require('remote').getGlobal('sharedObject').someProperty = 'new value';
```
```javascript
// 두 번째 페이지에서
console.log(require('remote').getGlobal('sharedObject').someProperty);
```
## 제작한 어플리케이션의 윈도우/트레이가 몇 분 후에나 나타납니다.
이러한 문제가 발생하는 이유는 보통 윈도우/트레이를 담은 변수에 가비지 컬렉션이 작동해서
@ -119,3 +147,7 @@ npm uninstall -g electron
[memory-management]: https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management
[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx
[electron-module]: https://www.npmjs.com/package/electron
[storage]: https://developer.mozilla.org/en-US/docs/Web/API/Storage
[local-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
[session-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
[indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API

View file

@ -59,9 +59,8 @@ electron/resources/
### Windows
`electron.exe`을 원하는 이름으로 변경할 수 있습니다.
그리고 [rcedit](https://github.com/atom/rcedit)
를 사용하여 아이콘을 변경할 수 있습니다.
[rcedit](https://github.com/atom/rcedit)를 통해 `electron.exe`을 원하는 이름으로
변경할 수 있고, 또한 아이콘과 기타 정보도 변경할 수 있습니다.
### OS X

View file

@ -263,6 +263,33 @@ var window = new BrowserWindow({...});
window.setProgressBar(0.5);
```
## 작업 표시줄의 아이콘 오버레이 (Windows)
Windows에선 작업 표시줄 버튼에 어플리케이션의 상태를 표시하는 작은 오버레이를 사용할
수 있습니다. MSDN에서 인용하자면 (영문):
> Icon overlays serve as a contextual notification of status, and are intended
> to negate the need for a separate notification area status icon to communicate
> that information to the user. For instance, the new mail status in Microsoft
> Outlook, currently shown in the notification area, can now be indicated
> through an overlay on the taskbar button. Again, you must decide during your
> development cycle which method is best for your application. Overlay icons are
> intended to supply important, long-standing status or notifications such as
> network status, messenger status, or new mail. The user should not be
> presented with constantly changing overlays or animations.
__작업 표시줄 버튼 위의 오버레이:__
![작업 표시줄 버튼 위의 오버레이](https://i-msdn.sec.s-msft.com/dynimg/IC420441.png)
윈도우에 오버레이 아이콘을 설정하려면 [BrowserWindow.setOverlayIcon][setoverlayicon]
API를 사용할 수 있습니다:
```javascript
var window = new BrowserWindow({...});
window.setOverlayIcon('path/to/overlay.png', 'Description for overlay');
```
## 대표 파일 제시 (OS X)
OS X는 창에서 대표 파일을 설정할 수 있습니다. 타이틀바에서 파일 아이콘이 있고, 사용자가
@ -283,13 +310,16 @@ window.setRepresentedFilename('/etc/passwd');
window.setDocumentEdited(true);
```
[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath
[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments
[setusertaskstasks]: ../api/app.md#appsetusertaskstasks
[setprogressbar]: ../api/browser-window.md#browserwindowsetprogressbarprogress
[setrepresentedfilename]: ../api/browser-window.md#browserwindowsetrepresentedfilenamefilename
[setdocumentedited]: ../api/browser-window.md#browserwindowsetdocumenteditededited
[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-os-x-windows
[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments-os-x-windows
[setusertaskstasks]: ../api/app.md#appsetusertaskstasks-windows
[setprogressbar]: ../api/browser-window.md#winsetprogressbarprogress
[setoverlayicon]: ../api/browser-window.md#winsetoverlayiconoverlay-description-windows-7
[setrepresentedfilename]: ../api/browser-window.md#winsetrepresentedfilenamefilename-os-x
[setdocumentedited]: ../api/browser-window.md#winsetdocumenteditededited-os-x
[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx
[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher
[setthumbarbuttons]: ../api/browser-window.md#browserwindowsetthumbarbuttonsbuttons
[trayballoon]: ../api/tray.md#traydisplayballoonoptions-windows
[setthumbarbuttons]: ../api/browser-window.md#winsetthumbarbuttonsbuttons-windows-7
[tray-balloon]: ../api/tray.md#traydisplayballoonoptions-windows
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx
[notification-spec]: https://developer.gnome.org/notification-spec/

View file

@ -12,7 +12,7 @@ Electron은 웹 페이지의 GUI를 사용합니다. 쉽게 말해 Electron은
### 메인 프로세스
Electron은 실행될 때 __메인 프로세스__로 불리는 `package.json``main` 스크립트를
Electron은 실행될 때 __메인 프로세스__ 로 불리는 `package.json``main` 스크립트를
호출합니다. 이 스크립트는 메인 프로세스에서 작동합니다. GUI 컴포넌트를 조작하거나 웹
페이지 창을 생성할 수 있습니다.
@ -43,6 +43,7 @@ API를 사용하여 low-level 수준으로 운영체제와 상호작용할 수
Electron에는 메인 프로세스와 랜더러 프로세스 사이에 통신을 할 수 있도록
[ipc](../api/ipc-renderer.md) 모듈을 제공하고 있습니다.
또는 [remote](../api/remote.md) 모듈을 사용하여 RPC 스타일로 통신할 수도 있습니다.
또한 FAQ에서 [다양한 객체를 공유하는 방법](share-data)도 소개하고 있습니다.
## 첫번째 Electron 앱 만들기
@ -211,3 +212,5 @@ $ cd electron-quick-start
# 어플리케이션의 종속성 모듈을 설치한 후 실행합니다
$ npm install && npm start
```
[share-data]: ../faq/electron-faq.md#어떻게-웹-페이지-간에-데이터를-공유할-수-있나요

View file

@ -48,7 +48,7 @@ var driver = new webdriver.Builder()
.withCapabilities({
chromeOptions: {
// 여기에 사용중인 Electron 바이너리의 경로를 지정하세요.
binary: '/Path-to-Your-App.app/Contents/MacOS/Atom',
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron',
}
})
.forBrowser('electron')

View file

@ -8,6 +8,10 @@ Electron은 라이센스상의 문제로 Widevine CDM 플러그인을 직접 제
따라서 플러그인을 얻으려면 먼저 사용할 Electron 빌드의 아키텍쳐와 버전에 맞춰 공식
Chrome 브라우저를 설치해야 합니다.
__참고:__ Chrome 브라우저의 메이저 버전은 Electron에서 사용하는 Chrome 버전과
같습니다, 만약 그렇지 않다면 `navigator.plugins`가 로드됐더라도 정상적으로 작동하지
않습니다.
### Windows & OS X
Chrome 브라우저에서 `chrome://components/`를 열고 `WidevineCdm`을 찾은 후 확실히

View file

@ -0,0 +1,67 @@
# The `window.open` function
Qunado `window.open` é chamado para criar uma nova janela de uma pagina web uma nova instância de `BrowserWindow` será criado para a `url` e um proxy será devolvido para o `windows.open`, para permitir que a página tenha limitado controle sobre ele.
O proxy tem funcionalidade limitada padrão implementada para ser compatível com as páginas web tradicionais.
Para controle total da nova janela você deveria criar um `BrowserWindow` diretamente
The newly created `BrowserWindow` will inherit parent window's options by
default, to override inherited options you can set them in the `features`
string.
O recém-criado `BrowserWindow` herdará as opções da janela pai por padrão, para substituir as opções herdadas você pode definilos no `features`(string).
### `window.open(url[, frameName][, features])`
* `url` String
* `frameName` String (opcional)
* `features` String (opcional)
Cria uma nova janela e retorna uma instância da classe `BrowserWindowProxy'.
A string `features` segue o formato padrão do browser, mas cada recurso (feature) tem que ser um campo de opções do `BrowserWindow`.
### `window.opener.postMessage(message, targetOrigin)`
* `message` String
* `targetOrigin` String
Envia uma mensagem para a janela pai com a origem especificada ou `*` preferência de origem não especificada.
Sends a message to the parent window with the specified origin or `*`
origin preference.
## Class: BrowserWindowProxy
O objeto `BrowserWindowProxy` é retornado de `window.open` e fornece uma funcionalidade limitada para a janela filha.
### `BrowserWindowProxy.blur()`
Remove o foco da janela filha.
### `BrowserWindowProxy.close()`
Forçadamente fecha a janela filha sem chamar o evento de descarregamento.
### `BrowserWindowProxy.closed`
Define como true após a janela filha ficar fechada.
### `BrowserWindowProxy.eval(code)`
* `code` String
Avalia o código na jánela filha.
### `BrowserWindowProxy.focus()`
Concentra-se a janela filha (traz a janela para frente)
### `BrowserWindowProxy.postMessage(message, targetOrigin)`
* `message` String
* `targetOrigin` String
Sends a message to the child window with the specified origin or `*` for no
origin preference.
In addition to these methods, the child window implements `window.opener` object
with no properties and a single method.

View file

@ -1,6 +1,6 @@
Пожалуйста, убедитесь, что вы используете документацию, которые соответствует вашей версии Electron.
Номер версии должен быть частью адреса страницы. Если это не так, вы
возможно,используете документицию ветки разработки, которая может содержать изменения api,
возможно, используете документацию ветки разработки, которая может содержать изменения api,
которые не совместимы с вашей версией Electron. Если это так,
Вы можете переключиться на другую версию документации в списке
[доступные версии](http://electron.atom.io/docs/) на atom.io, или

View file

@ -1,13 +1,19 @@
## 常见问题
+ [Electron 常见问题](faq/electron-faq.md)
## 向导
* [支持平台](tutorial/supported-platforms.md)
* [应用部署](tutorial/application-distribution.md)
* [应用打包](tutorial/application-packaging.md)
* [使用原生模块](tutorial/using-native-node-modules.md)
* [分发应用](tutorial/application-distribution.md)
* [提交应用到 Mac App Store](tutorial/mac-app-store-submission-guide.md)
* [打包应用](tutorial/application-packaging.md)
* [使用 Node 原生模块](tutorial/using-native-node-modules.md)
* [主进程调试](tutorial/debugging-main-process.md)
* [使用 Selenium 和 WebDriver](tutorial/using-selenium-and-webdriver.md)
* [调试工具扩展](tutorial/devtools-extension.md)
* [使用 PepperFlash 插件](tutorial/using-pepper-flash-plugin.md)
* [使用开发人员工具扩展](tutorial/devtools-extension.md)
* [使用 Pepper Flash 插件](tutorial/using-pepper-flash-plugin.md)
* [使用 Widevine CDM 插件](tutorial/using-widevine-cdm-plugin.md)
## 教程
@ -19,53 +25,55 @@
* [简介](api/synopsis.md)
* [进程对象](api/process.md)
* [支持的Chrome命令行开关](api/chrome-command-line-switches.md)
* [支持的 Chrome 命令行开关](api/chrome-command-line-switches.md)
* [环境变量](api/environment-variables.md)
定制的DOM元素:
自定义的 DOM 元素:
* [`File`对象](api/file-object.md)
* [`<webview>`标签](api/web-view-tag.md)
* [`window.open`函数](api/window-open.md)
* [`File` 对象](api/file-object.md)
* [`<webview>` 标签](api/web-view-tag.md)
* [`window.open` 函数](api/window-open.md)
主进程可用的模块:
主进程可用的模块:
* [app](api/app.md)
* [auto-updater](api/auto-updater.md)
* [browser-window](api/browser-window.md)
* [content-tracing](api/content-tracing.md)
* [autoUpdater](api/auto-updater.md)
* [BrowserWindow](api/browser-window.md)
* [contentTracing](api/content-tracing.md)
* [dialog](api/dialog.md)
* [global-shortcut](api/global-shortcut.md)
* [ipc (main process)](api/ipc-main-process.md)
* [menu](api/menu.md)
* [menu-item](api/menu-item.md)
* [power-monitor](api/power-monitor.md)
* [power-save-blocker](api/power-save-blocker.md)
* [globalShortcut](api/global-shortcut.md)
* [ipcMain](api/ipc-main.md)
* [Menu](api/menu.md)
* [MenuItem](api/menu-item.md)
* [powerMonitor](api/power-monitor.md)
* [powerSaveBlocker](api/power-save-blocker.md)
* [protocol](api/protocol.md)
* [session](api/session.md)
* [webContents](api/web-contents.md)
* [tray](api/tray.md)
* [Tray](api/tray.md)
渲染进程(网页)可用的模块:
在渲染进程(网页)内可用的模块:
* [ipc (renderer)](api/ipc-renderer.md)
* [desktopCapturer](api/desktop-capturer.md)
* [ipcRenderer](api/ipc-renderer.md)
* [remote](api/remote.md)
* [web-frame](api/web-frame.md)
* [webFrame](api/web-frame.md)
两种进程都可用的模块:
两种进程都可用的模块:
* [clipboard](api/clipboard.md)
* [crash-reporter](api/crash-reporter.md)
* [native-image](api/native-image.md)
* [crashReporter](api/crash-reporter.md)
* [nativeImage](api/native-image.md)
* [screen](api/screen.md)
* [shell](api/shell.md)
## 开发
* [码规范](development/coding-style.md)
* [码规范](development/coding-style.md)
* [源码目录结构](development/source-code-directory-structure.md)
* [与 NW.js (原名 node-webkit) 在技术上的差异](development/atom-shell-vs-node-webkit.md)
* [构建系统概](development/build-system-overview.md)
* [构建步骤 (Mac)](development/build-instructions-mac.md)
* [构建步骤 (Windows)](development/build-instructions-windows.md)
* [构建步骤 (Linux)](development/build-instructions-linux.md)
* [在调试中使用 SymbolServer](development/setting-up-symbol-server.md)
* [与 NW.js(原 node-webkit在技术上的差异](development/atom-shell-vs-node-webkit.md)
* [构建系统概](development/build-system-overview.md)
* [构建步骤Mac](development/build-instructions-mac.md)
* [构建步骤Windows](development/build-instructions-windows.md)
* [构建步骤Linux](development/build-instructions-linux.md)
* [在调试中使用 Symbol Server](development/setting-up-symbol-server.md)

View file

@ -1,46 +1,43 @@
# Accelerator
An accelerator is a string that represents a keyboard shortcut. It can contain
multiple modifiers and key codes, combined by the `+` character.
一个 `Accelerator` 是一个表示某个快捷键组合的字符串。它包含了用 `+` 连接的若干个按键。
Examples:
例如:
* `Command+A`
* `Ctrl+Shift+Z`
## Platform notice
## 运行平台相关的提示
On Linux and Windows, the `Command` key does not have any effect so
use `CommandOrControl` which represents `Command` on OS X and `Control` on
Linux and Windows to define some accelerators.
在 Linux 和 Windows 上,`Command` 键并不存在,因此我们通常用 `CommandOrControl` 来表示“在 OS X 下为 `Command` 键,但在
Linux 和 Windows 下为 `Control` 键。
The `Super` key is mapped to the `Windows` key on Windows and Linux and
`Cmd` on OS X.
`Super` 键是指 Linux 和 Windows 上的 `Windows` 键,但是在 OS X 下为 `Command` 键。
## Available modifiers
## 可用的功能按键
* `Command` (or `Cmd` for short)
* `Control` (or `Ctrl` for short)
* `CommandOrControl` (or `CmdOrCtrl` for short)
* `Command`(缩写为 `Cmd`
* `Control`(缩写为 `Ctrl`
* `CommandOrControl`(缩写为 `CmdOrCtrl`
* `Alt`
* `Shift`
* `Super`
## Available key codes
## 可用的普通按键
* `0` to `9`
* `A` to `Z`
* `F1` to `F24`
* Punctuations like `~`, `!`, `@`, `#`, `$`, etc.
* `0` `9`
* `A` `Z`
* `F1` `F24`
* 类似与 `~`、`!`、`@`、`#`、`$` 的标点符号。
* `Plus`
* `Space`
* `Backspace`
* `Delete`
* `Insert`
* `Return` (or `Enter` as alias)
* `Up`, `Down`, `Left` and `Right`
* `Home` and `End`
* `PageUp` and `PageDown`
* `Escape` (or `Esc` for short)
* `VolumeUp`, `VolumeDown` and `VolumeMute`
* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` and `MediaPlayPause`
* `Return`(和 `Enter` 等同)
* `Up`、`Down`、`Left` 和 `Right`
* `Home` `End`
* `PageUp` `PageDown`
* `Escape`(缩写为 `Esc`
* `VolumeUp`、`VolumeDown` 和 `VolumeMute`
* `MediaNextTrack`、`MediaPreviousTrack`、`MediaStop` 和 `MediaPlayPause`

View file

@ -11,11 +11,11 @@ app.on('window-all-closed', function() {
});
```
## 事件
## 事件列表
`app` 对象会触发以下的事件:
### 事件: 'will-finish-launching'
### 事件:'will-finish-launching'
当应用程序完成基础的启动的时候被触发。在 Windows 和 Linux 中,
`will-finish-launching` 事件与 `ready` 事件是相同的; 在 OS X 中,
@ -24,11 +24,11 @@ app.on('window-all-closed', function() {
在大多数的情况下,你应该只在 `ready` 事件处理器中完成所有的业务。
### 事件: 'ready'
### 事件:'ready'
当 Electron 完成初始化时被触发。
### 事件: 'window-all-closed'
### 事件:'window-all-closed'
当所有的窗口都被关闭时触发。
@ -36,20 +36,20 @@ app.on('window-all-closed', function() {
或者开发者调用了 `app.quit()` Electron 将会先尝试关闭所有的窗口再触发 `will-quit` 事件,
在这种情况下 `window-all-closed` 不会被触发。
### 事件: 'before-quit'
### 事件:'before-quit'
返回:
* `event` 事件
* `event` Event
在应用程序开始关闭它的窗口的时候被触发。
调用 `event.preventDefault()` 将会阻止终止应用程序的默认行为。
### 事件: 'will-quit'
### 事件:'will-quit'
返回:
* `event` 事件
* `event` Event
当所有的窗口已经被关闭,应用即将退出时被触发。
调用 `event.preventDefault()` 将会阻止终止应用程序的默认行为。
@ -57,20 +57,20 @@ app.on('window-all-closed', function() {
你可以在 `window-all-closed` 事件的描述中看到 `will-quit` 事件
`window-all-closed` 事件的区别。
### 事件: 'quit'
### 事件:'quit'
返回:
* `event` 事件
* `exitCode` 整数
* `event` Event
* `exitCode` Integer
当应用程序正在退出时触发。
### 事件: 'open-file' _OS X_
### 事件:'open-file' _OS X_
返回:
* `event` 事件
* `path` 字符串
* `event` Event
* `path` String
当用户想要在应用中打开一个文件时触发。`open-file` 事件常常在应用已经打开并且系统想要再次使用应用打开文件时被触发。
`open-file` 也会在一个文件被拖入 dock 且应用还没有运行的时候被触发。
@ -78,73 +78,74 @@ app.on('window-all-closed', function() {
如果你想处理这个事件,你应该调用 `event.preventDefault()`
在 Windows系统中, 你需要通过解析 process.argv 来获取文件路径。
### 事件: 'open-url' _OS X_
### 事件:'open-url' _OS X_
返回:
* `event` 事件
* `url` 字符串
* `event` Event
* `url` String
当用户想要在应用中打开一个url的时候被触发。URL格式必须要提前标识才能被你的应用打开。
如果你想处理这个事件,你应该调用 `event.preventDefault()`
### 事件: 'activate' _OS X_
### 事件:'activate' _OS X_
返回:
* `event` 事件
* `hasVisibleWindows` 布尔值
* `event` Event
* `hasVisibleWindows` Boolean
当应用被激活时触发,常用于点击应用的 dock 图标的时候。
### 事件: 'browser-window-blur'
### 事件:'browser-window-blur'
返回:
* `event` 事件
* `window` 浏览器窗口
* `event` Event
* `window` BrowserWindow
当一个 [浏览器窗口](browser-window.md) 失去焦点的时候触发。
当一个 [BrowserWindow](browser-window.md) 失去焦点的时候触发。
### 事件: 'browser-window-focus'
### 事件:'browser-window-focus'
返回:
* `event` 事件
* `window` 浏览器窗口
* `event` Event
* `window` BrowserWindow
当一个 [浏览器窗口](browser-window.md) 获得焦点的时候触发。
当一个 [BrowserWindow](browser-window.md) 获得焦点的时候触发。
### 事件: 'browser-window-created'
### 事件:'browser-window-created'
返回:
* `event` 事件
* `window` 浏览器窗口
* `event` Event
* `window` BrowserWindow
当一个 [浏览器窗口](browser-window.md) 被创建的时候触发。
当一个 [BrowserWindow](browser-window.md) 被创建的时候触发。
### 事件: 'certificate-error'
### 事件:'certificate-error'
返回:
* `event` 事件
* `webContents` [web组件](web-contents.md)
* `url` 字符串
* `certificateList` 对象
* `data` PEM 编码数据
* `issuerName` 发行者的公有名称
* `callback` 函数
* `event` Event
* `webContents` [WebContents](web-contents.md)
* `url` String - URL 地址
* `error` String - 错误码
* `certificate` Object
* `data` Buffer - PEM 编码数据
* `issuerName` String - 发行者的公有名称
* `callback` Function
Emitted when failed to verify the `certificate` for `url`, to trust the
certificate you should prevent the default behavior with
`event.preventDefault()` and call `callback(true)`.
当对 `url` 验证 `certificate` 证书失败的时候触发,如果需要信任这个证书,你需要阻止默认行为 `event.preventDefault()` 并且
调用 `callback(true)`
```javascript
session.on('certificate-error', function(event, webContents, url, error, certificate, callback) {
if (url == "https://github.com") {
// Verification logic.
// 验证逻辑。
event.preventDefault();
callback(true);
} else {
@ -153,37 +154,37 @@ session.on('certificate-error', function(event, webContents, url, error, certifi
});
```
### 事件: 'select-client-certificate'
### 事件:'select-client-certificate'
返回:
* `event` 事件
* `webContents` [web组件](web-contents.md)
* `url` 字符串
* `certificateList` 对象
* `data` PEM 编码数据
* `issuerName` 发行者的公有名称
* `callback` 函数
* `event` Event
* `webContents` [WebContents](web-contents.md)
* `url` String - URL 地址
* `certificateList` [Object]
* `data` Buffer - PEM 编码数据
* `issuerName` String - 发行者的公有名称
* `callback` Function
当一个客户端认证被请求的时候被触发。
The `url` corresponds to the navigation entry requesting the client certificate
and `callback` needs to be called with an entry filtered from the list.
Using `event.preventDefault()` prevents the application from using the first
certificate from the store.
`url` 指的是请求客户端认证的网页地址,调用 `callback` 时需要传入一个证书列表中的证书。
需要通过调用 `event.preventDefault()` 来防止应用自动使用第一个证书进行验证。如下所示:
```javascript
app.on('select-certificate', function(event, host, url, list, callback) {
event.preventDefault();
callback(list[0]);
})
```
### Event: 'login'
### 事件: 'login'
Returns:
返回:
* `event` Event
* `webContents` [Web组件](web-contents.md)
* `webContents` [WebContents](web-contents.md)
* `request` Object
* `method` String
* `url` URL
@ -196,11 +197,10 @@ Returns:
* `realm` String
* `callback` Function
`webContents` 要做验证时被触发。
`webContents` 要做进行一次 HTTP 登陆验证时被触发。
The default behavior is to cancel all authentications, to override this you
should prevent the default behavior with `event.preventDefault()` and call
`callback(username, password)` with the credentials.
默认情况下Electron 会取消所有的验证行为,如果需要重写这个行为,你需要用 `event.preventDefault()` 来阻止默认行为,并且
`callback(username, password)` 来进行验证。
```javascript
app.on('login', function(event, webContents, request, authInfo, callback) {
@ -208,22 +208,22 @@ app.on('login', function(event, webContents, request, authInfo, callback) {
callback('username', 'secret');
})
```
### 事件: 'gpu-process-crashed'
### 事件:'gpu-process-crashed'
当GPU进程崩溃时触发。
GPU 进程崩溃时触发。
## 方法
## 方法列表
`app` 对象拥有以下的方法:
**提示:** 有的方法只能用于特定的操作系统。
**请注意** 有的方法只能用于特定的操作系统。
### `app.quit()`
试图关掉所有的窗口。`before-quit` 事件将会最先触发。如果所有的窗口都被成功关闭了,
试图关掉所有的窗口。`before-quit` 事件将会最先触发。如果所有的窗口都被成功关闭了,
`will-quit` 事件将会被触发,默认下应用将会被关闭。
这个方法保证了所有的 `beforeunload``unload` 事件处理器被正确执行。会存在一个窗口被 `beforeunload` 事件处理器返回 `false` 取消退出的可能性
这个方法保证了所有的 `beforeunload``unload` 事件处理器被正确执行。假如一个窗口的 `beforeunload` 事件处理器返回 `false`,那么整个应用可能会取消退出
### `app.hide()` _OS X_
@ -241,30 +241,29 @@ app.on('login', function(event, webContents, request, authInfo, callback) {
所有的窗口会被立刻关闭,不会询问用户。`before-quit` 和 `will-quit` 这2个事件不会被触发
### `app.getAppPath()`
返回当前应用所在的文件路径。
### `app.getPath(name)`
* `name` 字符串
* `name` String
返回一个与 `name` 参数相关的特殊文件夹或文件路径。当失败时抛出一个 `Error`
你可以通过名称请求以下的路径:
* `home` 用户的 home 文件夹
* `appData` 所有用户的应用数据文件夹,默认对应:
* `home` 用户的 home 文件夹(主目录)
* `appData` 当前用户的应用数据文件夹,默认对应:
* `%APPDATA%` Windows 中
* `$XDG_CONFIG_HOME` or `~/.config` Linux 中
* `~/Library/Application Support` OS X 中
* `userData` 储存你应用程序设置文件的文件夹,默认是 `appData` 文件夹附加应用的名称
* `temp` 临时文件夹
* `userData` 储存你应用程序设置文件的文件夹,默认是 `appData` 文件夹附加应用的名称
* `temp` 临时文件夹
* `exe` 当前的可执行文件
* `module` `libchromiumcontent`.
* `desktop` 当前用户的桌面文件夹
* `documents` "我的文件夹"的路径.
* `module` `libchromiumcontent`
* `desktop` 当前用户的桌面文件夹
* `documents` 用户文档目录的路径
* `downloads` 用户下载目录的路径.
* `music` 用户音乐目录的路径.
* `pictures` 用户图片目录的路径.
@ -272,14 +271,14 @@ app.on('login', function(event, webContents, request, authInfo, callback) {
### `app.setPath(name, path)`
* `name` 字符串
* `path` 字符串
* `name` String
* `path` String
重写 `path` 参数到一个特别的文件夹或者是一个和 `name` 参数有关系的文件
重写某个 `name` 的路径为 `path``path` 可以是一个文件夹或者一个文件,这个和 `name` 的类型有关
如果这个路径指向的文件夹不存在,这个文件夹将会被这个方法创建。
如果错误则抛出 `Error`
如果错误则抛出 `Error`
你只可以指向 `app.getPath` 中定义过 `name` 的路径
`name` 参数只能使用 `app.getPath` 中定义过 `name`
默认情况下,网页的 cookie 和缓存都会储存在 `userData` 文件夹。
如果你想要改变这个位置,你需要在 `app` 模块中的 `ready` 事件被触发之前重写 `userData` 的路径。
@ -293,22 +292,20 @@ app.on('login', function(event, webContents, request, authInfo, callback) {
返回当前应用程序的 `package.json` 文件中的名称。
通常 `name` 字段是一个短的小写字符串,其命名规则按照 npm 中的模块命名规则。你应该单独列举一个
`productName` 字段,用于表示你的应用程序的完整名称,这个名称将会被 Electron 优先采用
由于 npm 的命名规则,通常 `name` 字段是一个短的小写字符串。但是应用名的完整名称通常是首字母大写的,你应该单独使用一个
`productName` 字段,用于表示你的应用程序的完整名称。Electron 会优先使用这个字段作为应用名
### `app.getLocale()`
返回当前应用程序的语言种类。
返回当前应用程序的语言。
### `app.addRecentDocument(path)` _OS X_ _Windows_
* `path` 字符串
* `path` String
最近访问的文档列表中添加 `path`
最近访问的文档列表中添加 `path`
这个列表由操作系统进行管理。在 Windows 中您可以通过任务条进行访问,在 OS X 中你可以通过dock 菜单进行访问。
这个列表由操作系统进行管理。在 Windows 中您可以通过任务条进行访问,在 OS X 中你可以通过 dock 菜单进行访问。
### `app.clearRecentDocuments()` _OS X_ _Windows_
@ -316,66 +313,55 @@ app.on('login', function(event, webContents, request, authInfo, callback) {
### `app.setUserTasks(tasks)` _Windows_
* `tasks``Task` 对象构成的数组
* `tasks` [Task] - 一个由 Task 对象构成的数组
`tasks` 添加到 Windows 中 JumpList 功能的 [Tasks][tasks] 分类中。
`tasks` 中的 `Task` 对象格式如下:
`Task` 对象
* `program` 字符串 - 执行程序的路径,通常你应该说明当前程序的路径为 `process.execPath` 字段。
* `arguments` 字符串 - 当 `program` 执行时的命令行参数。
* `title` 字符串 - JumpList 中显示的标题。
* `description` 字符串 - 对这个任务的描述。
* `iconPath` 字符串 - JumpList 中显示的 icon 的绝对路径可以是一个任意包含一个icon的资源文件。你通常可以通过指明 `process.execPath` 来显示程序中的icon。
* `iconIndex` 整数 - icon文件中的icon目录。如果一个icon文件包括了两个或多个icon就需要设置这个值以确定icon。如果一个文件仅包含一个icon那么这个值为0。
`Task` Object
* `program` String - 执行程序的路径,通常你应该说明当前程序的路径为 `process.execPath` 字段。
* `arguments` String - 当 `program` 执行时的命令行参数。
* `title` String - JumpList 中显示的标题。
* `description` String - 对这个任务的描述。
* `iconPath` String - JumpList 中显示的图标的绝对路径,可以是一个任意包含一个图标的资源文件。通常来说,你可以通过指明 `process.execPath` 来显示程序中的图标。
* `iconIndex` Integer - 图标文件中的采用的图标位置。如果一个图标文件包括了多个图标,就需要设置这个值以确定使用的是哪一个图标。
如果这个图标文件中只包含一个图标,那么这个值为 0。
### `app.allowNTLMCredentialsForAllDomains(allow)`
* `allow` Boolean
Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate
authentication - normally, Electron will only send NTLM/Kerberos credentials for
URLs that fall under "Local Intranet" sites (i.e. are in the same domain as you).
However, this detection often fails when corporate networks are badly configured,
so this lets you co-opt this behavior and enable it for all URLs.
动态设置是否总是为 HTTP NTLM 或 Negotiate 认证发送证书。通常来说Electron 只会对本地网络(比如和你处在一个域中的计算机)发
送 NTLM / Kerberos 证书。但是假如网络设置得不太好,可能这个自动探测会失效,所以你可以通过这个接口自定义 Electron 对所有 URL
的行为。
### `app.makeSingleInstance(callback)`
* `callback` Function
This method makes your application a Single Instance Application - instead of
allowing multiple instances of your app to run, this will ensure that only a
single instance of your app is running, and other instances signal this
instance and exit.
这个方法可以让你的应用在同一时刻最多只会有一个实例,否则你的应用可以被运行多次并产生多个实例。你可以利用这个接口保证只有一个实例正
常运行,其余的实例全部会被终止并退出。
`callback` will be called with `callback(argv, workingDirectory)` when a second
instance has been executed. `argv` is an Array of the second instance's command
line arguments, and `workingDirectory` is its current working directory. Usually
applications respond to this by making their primary window focused and
non-minimized.
如果多个实例同时运行,那么第一个被运行的实例中 `callback` 会以 `callback(argv, workingDirectory)` 的形式被调用。其余的实例
会被终止。
`argv` 是一个包含了这个实例的命令行参数列表的数组,`workingDirectory` 是这个实例目前的运行目录。通常来说,我们会用通过将应用在
主屏幕上激活,并且取消最小化,来提醒用户这个应用已经被打开了。
The `callback` is guaranteed to be executed after the `ready` event of `app`
gets emitted.
`app``ready` 事件后,`callback` 才有可能被调用。
This method returns `false` if your process is the primary instance of the
application and your app should continue loading. And returns `true` if your
process has sent its parameters to another instance, and you should immediately
quit.
如果当前实例为第一个实例,那么在这个方法将会返回 `false` 来保证它继续运行。否则将会返回 `true` 来让它立刻退出。
On OS X the system enforces single instance automatically when users try to open
a second instance of your app in Finder, and the `open-file` and `open-url`
events will be emitted for that. However when users start your app in command
line the system's single instance machanism will be bypassed and you have to
use this method to ensure single instance.
在 OS X 中,如果用户通过 Finder、`open-file` 或者 `open-url` 打开应用,系统会强制确保只有一个实例在运行。但是如果用户是通过
命令行打开,这个系统机制会被忽略,所以你仍然需要靠这个方法来保证应用为单实例运行的。
An example of activating the window of primary instance when a second instance
starts:
下面是一个简单的例子。我们可以通过这个例子了解如何确保应用为单实例运行状态。
```js
var myWindow = null;
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
// Someone tried to run a second instance, we should focus our window.
// 当另一个实例运行的时候,这里将会被调用,我们需要激活应用的窗口
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore();
myWindow.focus();
@ -383,104 +369,109 @@ var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory)
return true;
});
// 这个实例是多余的实例,需要退出
if (shouldQuit) {
app.quit();
return;
}
// Create myWindow, load the rest of the app, etc...
// 创建窗口、继续加载应用、应用逻辑等……
app.on('ready', function() {
});
```
### `app.setAppUserModelId(id)` _Windows_
* `id` String
改变 [Application User Model ID][app-user-model-id] 的 `id`.
改变当前应用的 [Application User Model ID][app-user-model-id] 为 `id`.
### `app.isAeroGlassEnabled()` _Windows_
This method returns `true` if [DWM composition](https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx)
(Aero Glass) is enabled, and `false` otherwise. You can use it to determine if
you should create a transparent window or not (transparent windows won't work
correctly when DWM composition is disabled).
如果 [DWM composition](https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx)(Aero Glass) 启用
了,那么这个方法会返回 `true`,否则是 `false`。你可以用这个方法来决定是否要开启透明窗口特效,因为如果用户没开启 DWM那么透明窗
口特效是无效的。
Usage example:
举个例子:
```js
let browserOptions = {width: 1000, height: 800};
// Make the window transparent only if the platform supports it.
// 只有平台支持的时候才使用透明窗口
if (process.platform !== 'win32' || app.isAeroGlassEnabled()) {
browserOptions.transparent = true;
browserOptions.frame = false;
}
// Create the window.
// 创建窗口
win = new BrowserWindow(browserOptions);
// Navigate.
// 转到某个网页
if (browserOptions.transparent) {
win.loadURL('file://' + __dirname + '/index.html');
} else {
// No transparency, so we load a fallback that uses basic styles.
// 没有透明特效,我们应该用某个只包含基本样式的替代解决方案。
win.loadURL('file://' + __dirname + '/fallback.html');
}
```
### `app.commandLine.appendSwitch(switch[, value])`
通过可选的参数 `value` 给 Chromium 命令行中添加一个开关。
Append a switch (with optional `value`) to Chromium's command line.
通过可选的参数 `value` 给 Chromium 中添加一个命令行开关。
**贴士:** 这不会影响 `process.argv` ,这个方法主要被开发者用于控制一些低层级的 Chromium 行为。
**注意** 这个方法不会影响 `process.argv`,我们通常用这个方法控制一些底层 Chromium 行为。
### `app.commandLine.appendArgument(value)`
给 Chromium 命令行中加入一个参数。这个参数是当前正在被引用的
给 Chromium 中直接添加一个命令行参数,这个参数 `value` 的引号和格式必须正确
**贴士:** 这不会影响 `process.argv`
**注意** 这个方法不会影响 `process.argv`
### `app.dock.bounce([type])` _OS X_
* `type` 字符串 (可选的) - 可以是 `critical``informational`。默认下是 `informational`
* `type` String - 可选参数,可以是 `critical``informational`。默认为 `informational`
输入 `critical`dock 中的 icon 将会开始弹跳直到应用被激活或者这个请求被取消。
传入的是 `critical`dock 中的应用将会开始弹跳,直到这个应用被激活或者这个请求被取消。
当输入 `informational`dock 中的 icon 只会弹跳一秒钟。
然而,这个请求仍然会激活,直到应用被激活或者请求被取消。
当传入的是 `informational`dock 中的图标只会弹跳一秒钟。但是,这个请求仍然会激活,直到应用被激活或者请求被取消。
返回一个表示这个请求的 ID。
这个方法返回的返回值表示这个请求的 ID。
### `app.dock.cancelBounce(id)` _OS X_
* `id` 整数
* `id` Integer
取消这个 `id` 对应的请求。
### `app.dock.setBadge(text)` _OS X_
* `text` 字符串
* `text` String
设置 dock 中显示的字符。
设置应用在 dock 中显示的字符
### `app.dock.getBadge()` _OS X_
返回 dock 中显示的字符。
返回应用在 dock 中显示的字符
### `app.dock.hide()` _OS X_
隐藏 dock 中的 icon
隐藏应用在 dock 中的图标
### `app.dock.show()` _OS X_
显示 dock 中的 icon
显示应用在 dock 中的图标
### `app.dock.setMenu(menu)` _OS X_
* `menu` 菜单
* `menu` [Menu](menu.md)
设置应用的 [dock 菜单][dock-menu].
### `app.dock.setIcon(image)` _OS X_
* `image` [NativeImage](native-image.md)
设置应用在 dock 中显示的图标。
[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx

View file

@ -0,0 +1,88 @@
# autoUpdater
这个模块提供了一个到 `Squirrel` 自动更新框架的接口。
## 平台相关的提示
虽然 `autoUpdater` 模块提供了一套各平台通用的接口,但是在每个平台间依然会有一些微小的差异。
### OS X
在 OS X 上,`autoUpdater` 模块依靠的是内置的 [Squirrel.Mac][squirrel-mac],这意味着你不需要依靠其他的设置就能使用。关于
更新服务器的配置,你可以通过阅读 [Server Support][server-support] 这篇文章来了解。
### Windows
在 Windows 上,你必须使用安装程序将你的应用装到用户的计算机上,所以比较推荐的方法是用 [grunt-electron-installer][installer] 这个模块来自动生成一个 Windows 安装向导。
Squirrel 自动生成的安装向导会生成一个带 [Application User Model ID][app-user-model-id] 的快捷方式。
Application User Model ID 的格式是 `com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE`, 比如
`com.squirrel.slack.Slack``com.squirrel.code.Code` 这样的。你应该在自己的应用中使用 `app.setAppUserModelId` 方法设置相同的 API不然 Windows 将不能正确地把你的应用固定在任务栏上。
服务器端的配置和 OS X 也是不一样的,你可以阅读 [Squirrel.Windows][squirrel-windows] 这个文档来获得详细信息。
### Linux
Linux 下没有任何的自动更新支持,所以我们推荐用各个 Linux 发行版的包管理器来分发你的应用。
## 事件列表
`autoUpdater` 对象会触发以下的事件:
### 事件:'error'
返回:
* `error` Error
当更新发生错误的时候触发。
### 事件:'checking-for-update'
当开始检查更新的时候触发。
### 事件:'update-available'
当发现一个可用更新的时候触发,更新包下载会自动开始。
### 事件:'update-not-available'
当没有可用更新的时候触发。
### 事件:'update-downloaded'
返回:
* `event` Event
* `releaseNotes` String - 新版本更新公告
* `releaseName` String - 新的版本号
* `releaseDate` Date - 新版本发布的日期
* `updateURL` String - 更新地址
在更新下载完成的时候触发。
在 Windows 上只有 `releaseName` 是有效的。
## 方法列表
`autoUpdater` 对象有以下的方法:
### `autoUpdater.setFeedURL(url)`
* `url` String
设置检查更新的 `url`,并且初始化自动更新。这个 `url` 一旦设置就无法更改。
### `autoUpdater.checkForUpdates()`
向服务端查询现在是否有可用的更新。在调用这个方法之前,必须要先调用 `setFeedURL`
### `autoUpdater.quitAndInstall()`
在下载完成后,重启当前的应用并且安装更新。这个方法应该仅在 `update-downloaded` 事件触发后被调用。
[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac
[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support
[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows
[installer]: https://github.com/atom/grunt-electron-installer
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx

View file

@ -0,0 +1,29 @@
# `File`对象
为了让用户能够通过HTML5的file API直接操作本地文件DOM的File接口提供了对本地文件的抽象。Electron在File接口中增加了一个path属性它是文件在系统中的真实路径。
---
获取拖动到APP中文件的真实路径的例子
```
<div id="holder">
Drag your file here
</div>
<script>
var holder = document.getElementById('holder');
holder.ondragover = function () {
return false;
};
holder.ondragleave = holder.ondragend = function () {
return false;
};
holder.ondrop = function (e) {
e.preventDefault();
var file = e.dataTransfer.files[0];
console.log('File you dragged here is', file.path);
return false;
};
</script>
```

View file

@ -0,0 +1,137 @@
# remote
`remote` 模块提供了一种在渲染进程网页和主进程之间进行进程间通讯IPC的简便途径。
Electron中, 与GUI相关的模块`dialog`, `menu` 等)只存在于主进程,而不在渲染进程中
。为了能从渲染进程中使用它们,需要用`ipc`模块来给主进程发送进程间消息。使用 `remote`
模块,可以调用主进程对象的方法,而无需显式地发送进程间消息,这类似于 Java 的 [RMI][rmi]。
下面是从渲染进程创建一个浏览器窗口的例子:
```javascript
const remote = require('electron').remote;
const BrowserWindow = remote.BrowserWindow;
var win = new BrowserWindow({ width: 800, height: 600 });
win.loadURL('https://github.com');
```
**注意:** 反向操作(从主进程访问渲染进程),可以使用[webContents.executeJavascript](web-contents.md#webcontentsexecutejavascriptcode-usergesture).
## 远程对象
`remote`模块返回的每个对象(包括函数)都代表了主进程中的一个对象(我们称之为远程对象或者远程函数)。
当调用远程对象的方法、执行远程函数或者使用远程构造器(函数)创建新对象时,其实就是在发送同步的进程间消息。
在上面的例子中, `BrowserWindow``win` 都是远程对象,然而
`new BrowserWindow` 并没有在渲染进程中创建 `BrowserWindow` 对象。
而是在主进程中创建了 `BrowserWindow` 对象,并在渲染进程中返回了对应的远程对象,即
`win` 对象。
请注意只有 [可枚举属性](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties) 才能通过 remote 进行访问.
## 远程对象的生命周期
Electron 确保在渲染进程中的远程对象存在(换句话说,没有被垃圾收集),那主进程中的对应对象也不会被释放。
当远程对象被垃圾收集之后,主进程中的对应对象才会被取消关联。
如果远程对象在渲染进程泄露了(即,存在某个表中但永远不会释放),那么主进程中的对应对象也一样会泄露,
所以你必须小心不要泄露了远程对象。If the remote object is leaked in the renderer process (e.g. stored in a map but
never freed), the corresponding object in the main process will also be leaked,
so you should be very careful not to leak remote objects.
不过,主要的值类型如字符串和数字,是传递的副本。
## 给主进程传递回调函数
在主进程中的代码可以从渲染进程——`remote`模块——中接受回调函数但是使用这个功能的时候必须非常非常小心。Code in the main process can accept callbacks from the renderer - for instance
the `remote` module - but you should be extremely careful when using this
feature.
首先为了避免死锁传递给主进程的回调函数会进行异步调用。所以不能期望主进程来获得传递过去的回调函数的返回值。First, in order to avoid deadlocks, the callbacks passed to the main process
are called asynchronously. You should not expect the main process to
get the return value of the passed callbacks.
比如,你不能主进程中给`Array.map`传递来自渲染进程的函数。
```javascript
// 主进程 mapNumbers.js
exports.withRendererCallback = function(mapper) {
return [1,2,3].map(mapper);
}
exports.withLocalCallback = function() {
return exports.mapNumbers(function(x) {
return x + 1;
});
}
```
```javascript
// 渲染进程
var mapNumbers = require("remote").require("./mapNumbers");
var withRendererCb = mapNumbers.withRendererCallback(function(x) {
return x + 1;
})
var withLocalCb = mapNumbers.withLocalCallback()
console.log(withRendererCb, withLocalCb) // [true, true, true], [2, 3, 4]
```
如你所见,渲染器回调函数的同步返回值没有按预期产生,与主进程中的一模一样的回调函数的返回值不同。
其次,传递给主进程的函数会持续到主进程对他们进行垃圾回收。
例如,下面的代码第一眼看上去毫无问题。给远程对象的`close`事件绑定了一个回调函数:
```javascript
remote.getCurrentWindow().on('close', function() {
// blabla...
});
```
但记住主进程会一直保持对这个回调函数的引用,除非明确的卸载它。如果不卸载,每次重新载入窗口都会再次绑定,这样每次重启就会泄露一个回调函数。
更严重的是,由于前面安装了回调函数的上下文已经被释放,所以当主进程的 `close` 事件触发的时候,会抛出异常。
为了避免这个问题,要确保对传递给主进程的渲染器的回调函数进行清理。可以清理事件处理器,或者明确告诉主进行取消来自已经退出的渲染器进程中的回调函数。
## 访问主进程中的内置模块
在主进程中的内置模块已经被添加为`remote`模块中的属性,所以可以直接像使用`electron`模块一样直接使用它们。
```javascript
const app = remote.app;
```
## 方法
`remote` 模块有以下方法:
### `remote.require(module)`
* `module` String
返回在主进程中执行 `require(module)` 所返回的对象。
### `remote.getCurrentWindow()`
返回该网页所属的 [`BrowserWindow`](browser-window.md) 对象。
### `remote.getCurrentWebContents()`
返回该网页的 [`WebContents`](web-contents.md) 对象
### `remote.getGlobal(name)`
* `name` String
返回在主进程中名为 `name` 的全局变量(即 `global[name]`) 。
### `remote.process`
返回主进程中的 `process` 对象。等同于
`remote.getGlobal('process')` 但是有缓存。
[rmi]: http://en.wikipedia.org/wiki/Java_remote_method_invocation

View file

@ -0,0 +1,139 @@
# Electron 常见问题
## Electron 会在什么时候升级到最新版本的 Chrome
通常来说,在稳定版的 Chrome 发布后两周内,我们会更新 Electron 内的 Chrome 版本。
我们只会使用 stable 版本的 Chrome。但如果在 beta 或 dev 版本中有一个重要的更新,我们会把补丁应用到现版本的 Chrome 上。
## Electron 会在什么时候升级到最新版本的 Node.js
我们通常会在最新版的 Node.js 发布后一个月左右将 Electron 更新到这个版本的 Node.js。我们通过这种方式来避免新版本的 Node.js
带来的 bug这种 bug 太常见了)。
Node.js 的新特性通常是由新版本的 V8 带来的。由于 Electron 使用的是 Chrome 浏览器中附带的 V8 引擎,所以 Electron 内往往已经
有了部分新版本 Node.js 才有的崭新特性。
## 如何在两个网页间共享数据?
在两个网页(渲染进程)间共享数据最简单的方法是使用浏览器中已经实现的 HTML5 API比较好的方案是用 [Storage API][storage]
[`localStorage`][local-storage][`sessionStorage`][session-storage] 或者 [IndexedDB][indexed-db]。
你还可以用 Electron 内的 IPC 机制实现。将数据存在主进程的某个全局变量中,然后在多个渲染进程中使用 `remote` 模块来访问它。
```javascript
// 在主进程中
global.sharedObject = {
someProperty: 'default value'
};
```
```javascript
// 在第一个页面中
require('remote').getGlobal('sharedObject').someProperty = 'new value';
```
```javascript
// 在第二个页面中
console.log(require('remote').getGlobal('sharedObject').someProperty);
```
## 为什么应用的窗口、托盘在一段时间后不见了?
这通常是因为用来存放窗口、托盘的变量被垃圾收集了。
你可以参考以下两篇文章来了解为什么会遇到这个问题。
* [内存管理][memory-management]
* [变量作用域][variable-scope]
如果你只是要一个快速的修复方案,你可以用下面的方式改变变量的作用域,防止这个变量被垃圾收集。
```javascript
app.on('ready', function() {
var tray = new Tray('/path/to/icon.png');
})
```
改为
```javascript
var tray = null;
app.on('ready', function() {
tray = new Tray('/path/to/icon.png');
})
```
## 在 Electron 中,我为什么不能用 jQuery、RequireJS、Meteor、AngularJS
因为 Electron 在运行环境中引入了 Node.js所以在 DOM 中有一些额外的变量,比如 `module`、`exports` 和 `require`。这导致
了许多库不能正常运行,因为它们也需要将同名的变量加入运行环境中。
我们可以通过禁用 Node.js 来解决这个问题,用如下的方式:
```javascript
// 在主进程中
var mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: false
}
});
```
假如你依然需要使用 Node.js 和 Electron 提供的 API你需要在引入那些库之前将这些变量重命名比如
```html
<head>
<script>
// 重命名 Electron 提供的 require
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
<script type="text/javascript" src="jquery.js"></script>
</head>
```
## 为什么 `require('electron').xxx` 的结果是 undefined
在使用 Electron 的提供的模块时,你可能会遇到和以下类似的错误:
```
> require('electron').webFrame.setZoomFactor(1.0);
Uncaught TypeError: Cannot read property 'setZoomLevel' of undefined
```
这是因为你在项目中或者在全局中安装了[npm 上获取的 `electron` 模块][electron-module],它把 Electron 的内置模块覆写了。
你可以通过以下方式输出 `electron` 模块的路径来确认你是否使用了正确的模块。
```javascript
console.log(require.resolve('electron'));
```
确认以下它是不是像下面这样的:
```
"/path/to/Electron.app/Contents/Resources/atom.asar/renderer/api/lib/exports/electron.js"
```
假如输出的路径类似于 `node_modules/electron/index.js`,那么你需要移除或者重命名 npm 上的 `electron` 模块。
```bash
npm uninstall electron
npm uninstall -g electron
```
如果你依然遇到了这个问题,你可能需要检查一下拼写或者是否在错误的进程中调用了这个模块。比如,
`require('electron').app` 只能在主进程中使用, 然而 `require('electron').webFrame` 只能在渲染进程中使用。
[memory-management]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management
[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx
[electron-module]: https://www.npmjs.com/package/electron
[storage]: https://developer.mozilla.org/en-US/docs/Web/API/Storage
[local-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
[session-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
[indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API

View file

@ -18,16 +18,31 @@
## 使用 node-inspector 来调试
__备注__ Electron 使用 node v0.11.13 版本,目前对 node-inspector支持的不是特别好
__备注__ Electron 目前对 node-inspector支持的不是特别好
如果你通过 node-inspector 的 console 来检查 `process` 对象,主进程就会崩溃。
### 1. 开始 [node-inspector][node-inspector] 服务
### 1. 确认你已经安装了 [node-gyp 所需工具](https://github.com/nodejs/node-gyp#installation)
### 2. 安装 [node-inspector][node-inspector]
```bash
$ node-inspector
$ npm install node-inspector
```
### 2. 打开 Electron 的调试模式
### 3. 安装 `node-pre-gyp` 的一个修订版
```bash
$ npm install git+https://git@github.com/enlight/node-pre-gyp.git#detect-electron-runtime-in-find
```
### 4. 为 Electron 重新编译 `node-inspector` `v8` 模块(将 target 参数修改为你的 Electron 的版本号)
```bash
$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-debug/ --dist-url=https://atom.io/download/atom-shell reinstall
$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-profiler/ --dist-url=https://atom.io/download/atom-shell reinstall
```
### 5. 打开 Electron 的调试模式
你也可以用调试参数来运行 Electron
@ -41,7 +56,13 @@ $ electron --debug=5858 your/app
$ electron --debug-brk=5858 your/app
```
### 3. 加载调试器界面
### 6. 使用 Electron 开启 [node-inspector][node-inspector] 服务
```bash
$ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin/inspector.js
```
### 7. 加载调试器界面
在 Chrome 中打开 http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858

View file

@ -127,7 +127,7 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/
在你完成了你的应用后,你可以按照[应用部署][4]指导发布一个版本,并且以已经打包好的形式运行应用。
[1]: https://github.com/atom/electron/blob/master/docs-translations/zh-CN/api/ipc-renderer.md
[1]: https://github.com/atom/electron/blob/master/docs-translations/zh-CN/api/ipc-main-process.md
[2]: https://github.com/atom/electron/blob/master/docs-translations/zh-CN/api/remote.md
[3]: https://github.com/atom/electron/releases
[4]: https://github.com/atom/electron/blob/master/docs-translations/zh-CN/tutorial/application-distribution.md

View file

@ -156,7 +156,7 @@ certificate you should prevent the default behavior with
`event.preventDefault()` and call `callback(true)`.
```javascript
session.on('certificate-error', function(event, webContents, url, error, certificate, callback) {
app.on('certificate-error', function(event, webContents, url, error, certificate, callback) {
if (url == "https://github.com") {
// Verification logic.
event.preventDefault();
@ -246,7 +246,7 @@ returning `false` in the `beforeunload` event handler.
### `app.hide()` _OS X_
Hides all application windows without minimising them.
Hides all application windows without minimizing them.
### `app.show()` _OS X_
@ -398,7 +398,7 @@ quit.
On OS X the system enforces single instance automatically when users try to open
a second instance of your app in Finder, and the `open-file` and `open-url`
events will be emitted for that. However when users start your app in command
line the system's single instance machanism will be bypassed and you have to
line the system's single instance mechanism will be bypassed and you have to
use this method to ensure single instance.
An example of activating the window of primary instance when a second instance
@ -413,7 +413,6 @@ var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory)
if (myWindow.isMinimized()) myWindow.restore();
myWindow.focus();
}
return true;
});
if (shouldQuit) {
@ -516,7 +515,7 @@ Shows the dock icon.
### `app.dock.setMenu(menu)` _OS X_
* `menu` Menu
* `menu` [Menu](menu.md)
Sets the application's [dock menu][dock-menu].

View file

@ -58,7 +58,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
* `alwaysOnTop` Boolean - Whether the window should always stay on top of
other windows. Default is `false`.
* `fullscreen` Boolean - Whether the window should show in fullscreen. When
explicity set to `false` the fullscreen button will be hidden or disabled
explicitly set to `false` the fullscreen button will be hidden or disabled
on OS X, or the maximize button will be disabled on Windows. Default is
`false`.
* `fullscreenable` Boolean - Whether the maximize/zoom button on OS X should
@ -458,7 +458,7 @@ Returns a boolean, whether the window is in fullscreen mode.
* `aspectRatio` The aspect ratio we want to maintain for some portion of the
content view.
* `extraSize` Object (optional) - The extra size not to be included while
maintaining the aspect ratio. Properties:
maintaining the aspect ratio.
* `width` Integer
* `height` Integer
@ -478,13 +478,11 @@ height areas you have within the overall content view.
### `win.setBounds(options[, animate])`
* `options` Object, properties:
* `options` Object
* `x` Integer
* `y` Integer
* `width` Integer
* `height` Integer
* `animate` Boolean (optional) _OS X_
Resizes and moves the window to `width`, `height`, `x`, `y`.
@ -717,7 +715,7 @@ Returns the pathname of the file the window represents.
* `edited` Boolean
Specifies whether the windows document has been edited, and the icon in title
bar will become grey when set to `true`.
bar will become gray when set to `true`.
### `win.isDocumentEdited()` _OS X_
@ -729,7 +727,7 @@ Whether the window's document has been edited.
### `win.capturePage([rect, ]callback)`
* `rect` Object (optional)- The area of page to be captured, properties:
* `rect` Object (optional) - The area of page to be captured
* `x` Integer
* `y` Integer
* `width` Integer
@ -802,27 +800,7 @@ Returns whether the window has a shadow. On Windows and Linux always returns
### `win.setThumbarButtons(buttons)` _Windows 7+_
`buttons` Array of `button` Objects:
`button` Object, properties:
* `icon` [NativeImage](native-image.md) - The icon showing in thumbnail
toolbar.
* `tooltip` String (optional) - The text of the button's tooltip.
* `flags` Array (optional) - Control specific states and behaviors
of the button. By default, it uses `enabled`. It can include following
Strings:
* `enabled` - The button is active and available to the user.
* `disabled` - The button is disabled. It is present, but has a visual
state indicating it will not respond to user action.
* `dismissonclick` - When the button is clicked, the taskbar button's
flyout closes immediately.
* `nobackground` - Do not draw a button border, use only the image.
* `hidden` - The button is not shown to the user.
* `noninteractive` - The button is enabled but not interactive; no
pressed button state is drawn. This value is intended for instances
where the button is used in a notification.
* `click` - Function
* `buttons` Array
Add a thumbnail toolbar with a specified set of buttons to the thumbnail image
of a window in a taskbar button layout. Returns a `Boolean` object indicates
@ -833,6 +811,29 @@ the limited room. Once you setup the thumbnail toolbar, the toolbar cannot be
removed due to the platform's limitation. But you can call the API with an empty
array to clean the buttons.
The `buttons` is an array of `Button` objects:
* `Button` Object
* `icon` [NativeImage](native-image.md) - The icon showing in thumbnail
toolbar.
* `click` Function
* `tooltip` String (optional) - The text of the button's tooltip.
* `flags` Array (optional) - Control specific states and behaviors of the
button. By default, it is `['enabled']`.
The `flags` is an array that can include following `String`s:
* `enabled` - The button is active and available to the user.
* `disabled` - The button is disabled. It is present, but has a visual state
indicating it will not respond to user action.
* `dismissonclick` - When the button is clicked, the thumbnail window closes
immediately.
* `nobackground` - Do not draw a button border, use only the image.
* `hidden` - The button is not shown to the user.
* `noninteractive` - The button is enabled but not interactive; no pressed
button state is drawn. This value is intended for instances where the button
is used in a notification.
### `win.showDefinitionForSelection()` _OS X_
Shows pop-up dictionary that searches the selected word on the page.

View file

@ -67,7 +67,6 @@ Writes `image` to the clipboard.
Returns the content in the clipboard as RTF.
### `clipboard.writeRtf(text[, type])`
* `text` String

View file

@ -155,7 +155,7 @@ called.
* `eventName` String
* `callback` Function
`callback` will will be called every time the given event occurs on any
`callback` will be called every time the given event occurs on any
process.
### `contentTracing.cancelWatchEvent()`

View file

@ -22,19 +22,16 @@ The `crash-reporter` module has the following methods:
### `crashReporter.start(options)`
`options` Object, properties:
* `productName` String, default: Electron.
* `companyName` String (**required**)
* `submitURL` String, (**required**)
* URL that crash reports will be sent to as POST.
* `autoSubmit` Boolean, default: `true`.
* Send the crash report without user interaction.
* `ignoreSystemCrashHandler` Boolean, default: `false`.
* `extra` Object
* An object you can define that will be sent along with the report.
* Only string properties are sent correctly.
* Nested objects are not supported.
* `options` Object
* `companyName` String
* `submitURL` String - URL that crash reports will be sent to as POST.
* `productName` String (optional) - Default is `Electron`.
* `autoSubmit` Boolean - Send the crash report without user interaction.
Default is `true`.
* `ignoreSystemCrashHandler` Boolean - Default is `false`.
* `extra` Object - An object you can define that will be sent along with the
report. Only string properties are sent correctly, Nested objects are not
supported.
You are required to call this method before using other `crashReporter`
APIs.

View file

@ -9,7 +9,7 @@ module.
## Sending Messages
It is also possible to send messages from the main process to the renderer
process, see [webContents.send](web-contents.md#webcontentssendchannel-arg1-arg2-) for more information.
process, see [webContents.send][web-contents-send] for more information.
* When sending a message, the event name is the `channel`.
* To reply a synchronous message, you need to set `event.returnValue`.
@ -48,37 +48,37 @@ ipcRenderer.send('asynchronous-message', 'ping');
The `ipcMain` module has the following method to listen for events:
### `ipcMain.on(channel, callback)`
### `ipcMain.on(channel, listener)`
* `channel` String - The event name.
* `callback` Function
* `channel` String
* `listener` Function
When the event occurs the `callback` is called with an `event` object and
arbitrary arguments.
Listens to `channel`, when a new message arrives `listener` would be called with
`listener(event, args...)`.
### `ipcMain.removeListener(channel, callback)`
### `ipcMain.once(channel, listener)`
* `channel` String - The event name.
* `callback` Function - The reference to the same function that you used for
`ipcMain.on(channel, callback)`
* `channel` String
* `listener` Function
Once done listening for messages, if you no longer want to activate this
callback and for whatever reason can't merely stop sending messages on the
channel, this function will remove the callback handler for the specified
channel.
Adds a one time `listener` function for the event. This `listener` is invoked
only the next time a message is sent to `channel`, after which it is removed.
### `ipcMain.removeAllListeners(channel)`
### `ipcMain.removeListener(channel, listener)`
* `channel` String - The event name.
* `channel` String
* `listener` Function
This removes *all* handlers to this ipc channel.
Removes the specified `listener` from the listener array for the specified
`channel`.
### `ipcMain.once(channel, callback)`
### `ipcMain.removeAllListeners([channel])`
Use this in place of `ipcMain.on()` to fire handlers meant to occur only once,
as in, they won't be activated after one call of `callback`
* `channel` String (optional)
## IPC Event
Removes all listeners, or those of the specified `channel`.
## Event object
The `event` object passed to the `callback` has the following methods:
@ -90,4 +90,6 @@ Set this to the value to be returned in a synchronous message.
Returns the `webContents` that sent the message, you can call
`event.sender.send` to reply to the asynchronous message, see
[webContents.send](web-contents.md#webcontentssendchannel-arg1-arg2-) for more information.
[webContents.send][web-contents-send] for more information.
[web-contents-send]: web-contents.md#webcontentssendchannel-arg1-arg2-

View file

@ -12,35 +12,35 @@ See [ipcMain](ipc-main.md) for code examples.
The `ipcRenderer` module has the following method to listen for events:
### `ipcRenderer.on(channel, callback)`
### `ipcRenderer.on(channel, listener)`
* `channel` String - The event name.
* `callback` Function
* `channel` String
* `listener` Function
When the event occurs the `callback` is called with an `event` object and
arbitrary arguments.
Listens to `channel`, when a new message arrives `listener` would be called with
`listener(event, args...)`.
### `ipcRenderer.removeListener(channel, callback)`
### `ipcRenderer.once(channel, listener)`
* `channel` String - The event name.
* `callback` Function - The reference to the same function that you used for
`ipcRenderer.on(channel, callback)`
* `channel` String
* `listener` Function
Once done listening for messages, if you no longer want to activate this
callback and for whatever reason can't merely stop sending messages on the
channel, this function will remove the callback handler for the specified
channel.
Adds a one time `listener` function for the event. This `listener` is invoked
only the next time a message is sent to `channel`, after which it is removed.
### `ipcRenderer.removeAllListeners(channel)`
### `ipcRenderer.removeListener(channel, listener)`
* `channel` String - The event name.
* `channel` String
* `listener` Function
This removes *all* handlers to this ipc channel.
Removes the specified `listener` from the listener array for the specified
`channel`.
### `ipcRenderer.once(channel, callback)`
### `ipcRenderer.removeAllListeners([channel])`
Use this in place of `ipcRenderer.on()` to fire handlers meant to occur only once,
as in, they won't be activated after one call of `callback`
* `channel` String (optional)
Removes all listeners, or those of the specified `channel`.
## Sending Messages
@ -48,30 +48,33 @@ The `ipcRenderer` module has the following methods for sending messages:
### `ipcRenderer.send(channel[, arg1][, arg2][, ...])`
* `channel` String - The event name.
* `channel` String
* `arg` (optional)
Send an event to the main process asynchronously via a `channel`, you can also
send arbitrary arguments. The main process handles it by listening for the
`channel` event with `ipcMain`.
Send a message to the main process asynchronously via `channel`, you can also
send arbitrary arguments. Arguments will be serialized in JSON internally and
hence no functions or prototype chain will be included.
The main process handles it by listening for `channel` with `ipcMain` module.
### `ipcRenderer.sendSync(channel[, arg1][, arg2][, ...])`
* `channel` String - The event name.
* `channel` String
* `arg` (optional)
Send an event to the main process synchronously via a `channel`, you can also
send arbitrary arguments.
Send a message to the main process synchronously via `channel`, you can also
send arbitrary arguments. Arguments will be serialized in JSON internally and
hence no functions or prototype chain will be included.
The main process handles it by listening for the `channel` event with
`ipcMain` and replies by setting `event.returnValue`.
The main process handles it by listening for `channel` with `ipcMain` module,
and replies by setting `event.returnValue`.
__Note:__ Sending a synchronous message will block the whole renderer process,
unless you know what you are doing you should never use it.
### `ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])`
* `channel` String - The event name.
* `channel` String
* `arg` (optional)
Like `ipcRenderer.send` but the event will be sent to the `<webview>` element in

View file

@ -26,12 +26,16 @@ Show the given file in a file manager. If possible, select the file.
Open the given file in the desktop's default manner.
### `shell.openExternal(url)`
### `shell.openExternal(url[, options])`
* `url` String
* `options` Object (optional) _OS X_
* `activate` Boolean - `true` to bring the opened application to the
foreground. The default is `true`.
Open the given external protocol URL in the desktop's default manner. (For
example, mailto: URLs in the user's default mail agent.)
example, mailto: URLs in the user's default mail agent.) Returns true if an
application was available to open the URL, false otherwise.
### `shell.moveItemToTrash(fullPath)`

View file

@ -32,6 +32,13 @@ __Platform limitations:__
install `libappindicator1` to make the tray icon work.
* App indicator will only be shown when it has a context menu.
* When app indicator is used on Linux, the `click` event is ignored.
* On Linux in order for changes made to individual `MenuItem`s to take effect,
you have to call `setContextMenu` again. For example:
```javascript
contextMenu.items[2].checked = false;
appIcon.setContextMenu(contextMenu);
```
If you want to keep exact same behaviors on all platforms, you should not
rely on the `click` event and always attach a context menu to the tray icon.

View file

@ -259,8 +259,8 @@ Returns:
* `result` Object
* `requestId` Integer
* `finalUpdate` Boolean - Indicates if more responses are to follow.
* `matches` Integer (Optional) - Number of Matches.
* `selectionArea` Object (Optional) - Coordinates of first match region.
* `matches` Integer (optional) - Number of Matches.
* `selectionArea` Object (optional) - Coordinates of first match region.
Emitted when a result is available for
[`webContents.findInPage`](web-contents.md#webcontentsfindinpage) request.
@ -310,7 +310,7 @@ The `webContents` object has the following instance methods:
### `webContents.loadURL(url[, options])`
* `url` URL
* `options` Object (optional), properties:
* `options` Object (optional)
* `httpReferrer` String - A HTTP Referrer url.
* `userAgent` String - A user agent originating the request.
* `extraHeaders` String - Extra headers separated by "\n"
@ -503,7 +503,7 @@ Inserts `text` to the focused element.
### `webContents.findInPage(text[, options])`
* `text` String - Content to be searched, must not be empty.
* `options` Object (Optional)
* `options` Object (optional)
* `forward` Boolean - Whether to search forward or backward, defaults to `true`.
* `findNext` Boolean - Whether the operation is first request or a follow up,
defaults to `false`.
@ -556,11 +556,10 @@ when the JS promise is rejected.
### `webContents.print([options])`
`options` Object (optional), properties:
* `silent` Boolean - Don't ask user for print settings, defaults to `false`
* `printBackground` Boolean - Also prints the background color and image of
the web page, defaults to `false`.
* `options` Object (optional)
* `silent` Boolean - Don't ask user for print settings. Default is `false`.
* `printBackground` Boolean - Also prints the background color and image of
the web page. Default is `false`.
Prints window's web page. When `silent` is set to `false`, Electron will pick
up system's default printer and default settings for printing.
@ -574,31 +573,22 @@ size.
### `webContents.printToPDF(options, callback)`
`options` Object, properties:
* `marginsType` Integer - Specify the type of margins to use
* 0 - default
* 1 - none
* 2 - minimum
* `pageSize` String - Specify page size of the generated PDF.
* `A5`
* `A4`
* `A3`
* `Legal`
* `Letter`
* `Tabloid`
* `printBackground` Boolean - Whether to print CSS backgrounds.
* `printSelectionOnly` Boolean - Whether to print selection only.
* `landscape` Boolean - `true` for landscape, `false` for portrait.
`callback` Function - `function(error, data) {}`
* `error` Error
* `data` Buffer - PDF file content.
* `options` Object
* `marginsType` Integer - Specifies the type of margins to use. Uses 0 for
default margin, 1 for no margin, and 2 for minimum margin.
* `pageSize` String - Specify page size of the generated PDF. Can be `A3`,
`A4`, `A5`, `Legal`, `Letter` and `Tabloid`.
* `printBackground` Boolean - Whether to print CSS backgrounds.
* `printSelectionOnly` Boolean - Whether to print selection only.
* `landscape` Boolean - `true` for landscape, `false` for portrait.
* `callback` Function
Prints window's web page as PDF with Chromium's preview printing custom
settings.
The `callback` will be called with `callback(error, data)` on completion. The
`data` is a `Buffer` that contains the generated PDF data.
By default, an empty `options` will be regarded as:
```javascript
@ -651,7 +641,7 @@ Removes the specified path from DevTools workspace.
### `webContents.openDevTools([options])`
* `options` Object (optional). Properties:
* `options` Object (optional)
* `detach` Boolean - opens DevTools in a new window
Opens the devtools.
@ -693,8 +683,11 @@ Opens the developer tools for the service worker context.
* `arg` (optional)
Send an asynchronous message to renderer process via `channel`, you can also
send arbitrary arguments. The renderer process can handle the message by
listening to the `channel` event with the `ipcRenderer` module.
send arbitrary arguments. Arguments will be serialized in JSON internally and
hence no functions or prototype chain will be included.
The renderer process can handle the message by listening to `channel` with the
`ipcRenderer` module.
An example of sending messages from the main process to the renderer process:
@ -849,6 +842,10 @@ win.webContents.on('did-finish-load', function() {
Returns the [session](session.md) object used by this webContents.
### `webContents.hostWebContents`
Returns the `WebContents` that might own this `WebContents`.
### `webContents.devToolsWebContents`
Get the `WebContents` of DevTools for this `WebContents`.

View file

@ -184,7 +184,7 @@ webview.addEventListener("dom-ready", function() {
### `<webview>.loadURL(url[, options])`
* `url` URL
* `options` Object (optional), properties:
* `options` Object (optional)
* `httpReferrer` String - A HTTP Referrer url.
* `userAgent` String - A user agent originating the request.
* `extraHeaders` String - Extra headers separated by "\n"
@ -382,7 +382,7 @@ Inserts `text` to the focused element.
### `<webview>.findInPage(text[, options])`
* `text` String - Content to be searched, must not be empty.
* `options` Object (Optional)
* `options` Object (optional)
* `forward` Boolean - Whether to search forward or backward, defaults to `true`.
* `findNext` Boolean - Whether the operation is first request or a follow up,
defaults to `false`.
@ -438,6 +438,10 @@ Sends an input `event` to the page.
See [webContents.sendInputEvent](web-contents.md##webcontentssendinputeventevent)
for detailed description of `event` object.
### `<webview>.getWebContents()`
Returns the [WebContents](web-contents.md) associated with this `webview`.
## DOM events
The following DOM events are available to the `webview` tag:
@ -522,7 +526,7 @@ Returns:
* `explicitSet` Boolean
Fired when page title is set during navigation. `explicitSet` is false when
title is synthesised from file url.
title is synthesized from file url.
### Event: 'page-favicon-updated'
@ -567,8 +571,8 @@ Returns:
* `result` Object
* `requestId` Integer
* `finalUpdate` Boolean - Indicates if more responses are to follow.
* `matches` Integer (Optional) - Number of Matches.
* `selectionArea` Object (Optional) - Coordinates of first match region.
* `matches` Integer (optional) - Number of Matches.
* `selectionArea` Object (optional) - Coordinates of first match region.
Fired when a result is available for
[`webview.findInPage`](web-view-tag.md#webviewtagfindinpage) request.

View file

@ -18,6 +18,34 @@ New features of Node.js are usually brought by V8 upgrades, since Electron is
using the V8 shipped by Chrome browser, the shiny new JavaScript feature of a
new Node.js version is usually already in Electron.
## How to share data between web pages?
To share data between web pages (the renderer processes) the simplest way is to
use HTML5 APIs which are already available in browsers. Good candidates are
[Storage API][storage], [`localStorage`][local-storage],
[`sessionStorage`][session-storage], and [IndexedDB][indexed-db].
Or you can use the IPC system, which are specific to Electron, to store objects
in the main process as a global variable, and then to access them from the
renderers through the `remote` module:
```javascript
// In the main process.
global.sharedObject = {
someProperty: 'default value'
};
```
```javascript
// In page 1.
require('remote').getGlobal('sharedObject').someProperty = 'new value';
```
```javascript
// In page 2.
console.log(require('remote').getGlobal('sharedObject').someProperty);
```
## My app's window/tray disappeared after a few minutes.
This happens when the variable which is used to store the window/tray gets
@ -120,3 +148,7 @@ is only available in renderer processes.
[memory-management]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management
[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx
[electron-module]: https://www.npmjs.com/package/electron
[storage]: https://developer.mozilla.org/en-US/docs/Web/API/Storage
[local-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
[session-storage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
[indexed-db]: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API

View file

@ -271,6 +271,33 @@ var window = new BrowserWindow({...});
window.setProgressBar(0.5);
```
## Icon Overlays in Taskbar (Windows)
On Windows a taskbar button can use a small overlay to display application
status, as quoted from MSDN:
> Icon overlays serve as a contextual notification of status, and are intended
> to negate the need for a separate notification area status icon to communicate
> that information to the user. For instance, the new mail status in Microsoft
> Outlook, currently shown in the notification area, can now be indicated
> through an overlay on the taskbar button. Again, you must decide during your
> development cycle which method is best for your application. Overlay icons are
> intended to supply important, long-standing status or notifications such as
> network status, messenger status, or new mail. The user should not be
> presented with constantly changing overlays or animations.
__Overlay on taskbar button:__
![Overlay on taskbar button](https://i-msdn.sec.s-msft.com/dynimg/IC420441.png)
To set the overlay icon for a window, you can use the
[BrowserWindow.setOverlayIcon][setoverlayicon] API:
```javascript
var window = new BrowserWindow({...});
window.setOverlayIcon('path/to/overlay.png', 'Description for overlay');
```
## Represented File of Window (OS X)
On OS X a window can set its represented file, so the file's icon can show in
@ -294,15 +321,16 @@ window.setRepresentedFilename('/etc/passwd');
window.setDocumentEdited(true);
```
[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath
[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments
[setusertaskstasks]: ../api/app.md#appsetusertaskstasks
[setprogressbar]: ../api/browser-window.md#browserwindowsetprogressbarprogress
[setrepresentedfilename]: ../api/browser-window.md#browserwindowsetrepresentedfilenamefilename
[setdocumentedited]: ../api/browser-window.md#browserwindowsetdocumenteditededited
[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-os-x-windows
[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments-os-x-windows
[setusertaskstasks]: ../api/app.md#appsetusertaskstasks-windows
[setprogressbar]: ../api/browser-window.md#winsetprogressbarprogress
[setoverlayicon]: ../api/browser-window.md#winsetoverlayiconoverlay-description-windows-7
[setrepresentedfilename]: ../api/browser-window.md#winsetrepresentedfilenamefilename-os-x
[setdocumentedited]: ../api/browser-window.md#winsetdocumenteditededited-os-x
[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx
[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher
[setthumbarbuttons]: ../api/browser-window.md#browserwindowsetthumbarbuttonsbuttons
[setthumbarbuttons]: ../api/browser-window.md#winsetthumbarbuttonsbuttons-windows-7
[tray-balloon]: ../api/tray.md#traydisplayballoonoptions-windows
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx
[notification-spec]: https://developer.gnome.org/notification-spec/

View file

@ -34,8 +34,8 @@ The main process creates web pages by creating `BrowserWindow` instances. Each
is also terminated.
The main process manages all web pages and their corresponding renderer
processes. Each renderer process is isolated and only cares
about the web page running in it.
processes. Each renderer process is isolated and only cares about the web page
running in it.
In web pages, calling native GUI related APIs is not allowed because managing
native GUI resources in web pages is very dangerous and it is easy to leak
@ -43,9 +43,11 @@ resources. If you want to perform GUI operations in a web page, the renderer
process of the web page must communicate with the main process to request that
the main process perform those operations.
In Electron, we have provided the [ipc](../api/ipc-renderer.md) module for
communication between the main process and renderer process. There is also a
[remote](../api/remote.md) module for RPC style communication.
In Electron, we have several ways to communicate between the main process and
renderer processes. Like [`ipcRenderer`](../api/ipc-renderer.md) and
[`ipcMain`](../api/ipc-main.md) modules for sending messages, and the
[remote](../api/remote.md) module for RPC style communication. There is also
an FAQ entry on [how to share data between web pages][share-data].
## Write your First Electron App
@ -205,3 +207,5 @@ $ cd electron-quick-start
# Install dependencies and run the app
$ npm install && npm start
```
[share-data]: ../faq/electron-faq.md#how-to-share-data-between-web-pages

View file

@ -49,7 +49,7 @@ var driver = new webdriver.Builder()
.withCapabilities({
chromeOptions: {
// Here is the path to your Electron binary.
binary: '/Path-to-Your-App.app/Contents/MacOS/Atom',
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron',
}
})
.forBrowser('electron')

View file

@ -8,6 +8,10 @@ Electron doesn't ship with the Widevine CDM plugin for license reasons, to get
it, you need to install the official Chrome browser first, which should match
the architecture and Chrome version of the Electron build you use.
__Note:__ The major version of Chrome browser has to be the same with the Chrome
version used by Electron, otherwise the plugin will not work even though
`navigator.plugins` would show it has been loaded.
### Windows & OS X
Open `chrome://components/` in Chrome browser, find `WidevineCdm` and make

View file

@ -41,6 +41,7 @@
'atom/common/api/lib/clipboard.js',
'atom/common/api/lib/crash-reporter.js',
'atom/common/api/lib/deprecate.js',
'atom/common/api/lib/deprecations.js',
'atom/common/api/lib/exports/electron.js',
'atom/common/api/lib/native-image.js',
'atom/common/api/lib/shell.js',

View file

@ -1,9 +1,9 @@
{
"name": "electron",
"version": "0.36.7",
"version": "0.36.8",
"devDependencies": {
"asar": "^0.9.0",
"eslint": "^1.10.3",
"asar": "^0.10.0",
"eslint": "^2.1.0",
"request": "*"
},
"optionalDependencies": {

View file

@ -38,6 +38,7 @@ TARGET_BINARIES = {
'libGLESv2.dll',
'msvcp120.dll',
'msvcr120.dll',
'ffmpeg.dll',
'node.dll',
'pdf.dll',
'content_resources_200_percent.pak',
@ -51,6 +52,7 @@ TARGET_BINARIES = {
PROJECT_NAME, # 'electron'
'content_shell.pak',
'icudtl.dat',
'libffmpeg.so',
'libnode.so',
'natives_blob.bin',
'snapshot_blob.bin',
@ -97,6 +99,7 @@ def main():
create_dist_zip()
create_chrome_binary_zip('chromedriver', get_chromedriver_version())
create_chrome_binary_zip('mksnapshot', ATOM_SHELL_VERSION)
create_ffmpeg_zip()
create_symbols_zip()
@ -203,6 +206,24 @@ def create_chrome_binary_zip(binary, version):
make_zip(zip_file, files, [])
def create_ffmpeg_zip():
dist_name = 'ffmpeg-{0}-{1}-{2}.zip'.format(
ATOM_SHELL_VERSION, get_platform_key(), get_target_arch())
zip_file = os.path.join(SOURCE_ROOT, 'dist', dist_name)
if PLATFORM == 'darwin':
ffmpeg_name = 'libffmpeg.dylib'
elif PLATFORM == 'linux':
ffmpeg_name = 'libffmpeg.so'
elif PLATFORM == 'win32':
ffmpeg_name = 'ffmpeg.dll'
shutil.copy2(os.path.join(CHROMIUM_DIR, '..', 'ffmpeg', ffmpeg_name),
DIST_DIR)
with scoped_cwd(DIST_DIR):
make_zip(zip_file, [ffmpeg_name, 'LICENSE', 'LICENSES.chromium.html'], [])
def create_symbols_zip():
dist_name = '{0}-{1}-{2}-{3}-symbols.zip'.format(PROJECT_NAME,
ATOM_SHELL_VERSION,

View file

@ -4,6 +4,7 @@ import glob
import os
import sys
from lib.config import PLATFORM
from lib.util import execute
@ -13,6 +14,10 @@ SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
def main():
os.chdir(SOURCE_ROOT)
# Skip eslint on our Windows build machine for now.
if PLATFORM == 'win32' and os.getenv('JANKY_SHA1'):
return
eslint = os.path.join(SOURCE_ROOT, 'node_modules', '.bin', 'eslint')
if sys.platform in ['win32', 'cygwin']:
eslint += '.cmd'

View file

@ -8,7 +8,7 @@ import sys
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent'
LIBCHROMIUMCONTENT_COMMIT = 'ad63d8ba890bcaad2f1b7e6de148b7992f4d3af7'
LIBCHROMIUMCONTENT_COMMIT = '599c8941e1884e155218ec1013cba9fc5c7c7072'
PLATFORM = {
'cygwin': 'win32',

View file

@ -35,9 +35,6 @@ DSYM_NAME = '{0}-{1}-{2}-{3}-dsym.zip'.format(PROJECT_NAME,
ATOM_SHELL_VERSION,
get_platform_key(),
get_target_arch())
MKSNAPSHOT_NAME = 'mksnapshot-{0}-{1}-{2}.zip'.format(ATOM_SHELL_VERSION,
get_platform_key(),
get_target_arch())
def main():
@ -89,12 +86,19 @@ def main():
if PLATFORM == 'darwin':
upload_atom_shell(github, release, os.path.join(DIST_DIR, DSYM_NAME))
# Upload free version of ffmpeg.
ffmpeg = 'ffmpeg-{0}-{1}-{2}.zip'.format(
ATOM_SHELL_VERSION, get_platform_key(), get_target_arch())
upload_atom_shell(github, release, os.path.join(DIST_DIR, ffmpeg))
# Upload chromedriver and mksnapshot for minor version update.
if parse_version(args.version)[2] == '0':
chromedriver = 'chromedriver-{0}-{1}-{2}.zip'.format(
get_chromedriver_version(), get_platform_key(), get_target_arch())
upload_atom_shell(github, release, os.path.join(DIST_DIR, chromedriver))
upload_atom_shell(github, release, os.path.join(DIST_DIR, MKSNAPSHOT_NAME))
mksnapshot = 'mksnapshot-{0}-{1}-{2}.zip'.format(
ATOM_SHELL_VERSION, get_platform_key(), get_target_arch())
upload_atom_shell(github, release, os.path.join(DIST_DIR, mksnapshot))
if PLATFORM == 'win32' and not tag_exists:
# Upload node headers.

Some files were not shown because too many files have changed in this diff Show more