mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
10 Commits
v10.0.0-be
...
v11.0.0-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2029ff1903 | ||
|
|
9bc5e98238 | ||
|
|
762f7bcca2 | ||
|
|
75847a0c5b | ||
|
|
e3c2ec9f7c | ||
|
|
fdf40ce07a | ||
|
|
82924679fe | ||
|
|
f373cc770f | ||
|
|
78d74bf8b4 | ||
|
|
5ed2512881 |
@@ -1 +1 @@
|
||||
10.0.0-beta.2
|
||||
11.0.0-nightly.20200525
|
||||
@@ -71,6 +71,7 @@ steps:
|
||||
ELECTRON_TEST_RESULTS_DIR: junit
|
||||
MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap'
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
MOCHA_TIMEOUT: 120000
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results'
|
||||
|
||||
@@ -66,7 +66,7 @@ if (defines['ENABLE_VIEWS_API'] === 'false') {
|
||||
|
||||
const alias = {}
|
||||
for (const ignoredModule of ignoredModules) {
|
||||
alias[ignoredModule] = path.resolve(electronRoot, 'lib/common/dummy.js')
|
||||
alias[ignoredModule] = path.resolve(electronRoot, 'lib/common/dummy.ts')
|
||||
}
|
||||
|
||||
module.exports = ({
|
||||
|
||||
@@ -92,7 +92,6 @@ These individual tutorials expand on topics discussed in the guide above.
|
||||
* Electron Releases & Developer Feedback
|
||||
* [Versioning Policy](tutorial/electron-versioning.md)
|
||||
* [Release Timelines](tutorial/electron-timelines.md)
|
||||
* [App Feedback Program](tutorial/app-feedback-program.md)
|
||||
* [Packaging App Source Code with asar](tutorial/application-packaging.md)
|
||||
* [Generating asar Archives](tutorial/application-packaging.md#generating-asar-archives)
|
||||
* [Using asar Archives](tutorial/application-packaging.md#using-asar-archives)
|
||||
|
||||
@@ -39,7 +39,7 @@ Returns:
|
||||
* `message` String - The actual console message
|
||||
* `versionId` Number - The version ID of the service worker that sent the log message
|
||||
* `source` String - The type of source for this message. Can be `javascript`, `xml`, `network`, `console-api`, `storage`, `app-cache`, `rendering`, `security`, `deprecation`, `worker`, `violation`, `intervention`, `recommendation` or `other`.
|
||||
* `level` Number - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`.
|
||||
* `level` Number - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`.
|
||||
* `sourceUrl` String - The URL the message came from
|
||||
* `lineNumber` Number - The line number of the source that triggered this console message
|
||||
|
||||
|
||||
@@ -737,9 +737,9 @@ Emitted when a `<webview>` has been attached to this web contents.
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `level` Integer
|
||||
* `message` String
|
||||
* `line` Integer
|
||||
* `level` Integer - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`.
|
||||
* `message` String - The actual console message
|
||||
* `line` Integer - The line number of the source that triggered this console message
|
||||
* `sourceId` String
|
||||
|
||||
Emitted when the associated window logs a console message.
|
||||
@@ -907,10 +907,10 @@ Returns `String` - The URL of the current web page.
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
let win = new BrowserWindow({ width: 800, height: 600 })
|
||||
win.loadURL('http://github.com').then(() => {
|
||||
const currentURL = win.webContents.getURL()
|
||||
console.log(currentURL)
|
||||
})
|
||||
win.loadURL('http://github.com')
|
||||
|
||||
let currentURL = win.webContents.getURL()
|
||||
console.log(currentURL)
|
||||
```
|
||||
|
||||
#### `contents.getTitle()`
|
||||
|
||||
@@ -755,9 +755,9 @@ Fired when page leaves fullscreen triggered by HTML API.
|
||||
|
||||
Returns:
|
||||
|
||||
* `level` Integer
|
||||
* `message` String
|
||||
* `line` Integer
|
||||
* `level` Integer - The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and `error`.
|
||||
* `message` String - The actual console message
|
||||
* `line` Integer - The line number of the source that triggered this console message
|
||||
* `sourceId` String
|
||||
|
||||
Fired when the guest window logs a console message.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Electron App Feedback Program
|
||||
|
||||
Electron is working on building a streamlined release process and having faster releases. To help with that, we have the App Feedback Program for large-scale Electron apps to test our beta releases and report app-specific issues to the Electron team. We use this program to help us prioritize work and get applications upgraded to the next stable release as soon as possible. There are a few requirements we expect from participants, such as attending short, online weekly check-ins. Please visit the [blog post](https://electronjs.org/blog/app-feedback-program) for details and sign-up.
|
||||
@@ -136,11 +136,11 @@ auto_filenames = {
|
||||
|
||||
sandbox_bundle_deps = [
|
||||
"lib/browser/api/module-names.ts",
|
||||
"lib/common/api/clipboard.js",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
@@ -189,15 +189,15 @@ auto_filenames = {
|
||||
"lib/browser/api/auto-updater/auto-updater-native.js",
|
||||
"lib/browser/api/auto-updater/auto-updater-win.js",
|
||||
"lib/browser/api/auto-updater/squirrel-update-win.js",
|
||||
"lib/browser/api/browser-view.js",
|
||||
"lib/browser/api/browser-view.ts",
|
||||
"lib/browser/api/browser-window.js",
|
||||
"lib/browser/api/content-tracing.js",
|
||||
"lib/browser/api/content-tracing.ts",
|
||||
"lib/browser/api/crash-reporter.ts",
|
||||
"lib/browser/api/desktop-capturer.ts",
|
||||
"lib/browser/api/dialog.js",
|
||||
"lib/browser/api/exports/electron.ts",
|
||||
"lib/browser/api/global-shortcut.js",
|
||||
"lib/browser/api/in-app-purchase.js",
|
||||
"lib/browser/api/global-shortcut.ts",
|
||||
"lib/browser/api/in-app-purchase.ts",
|
||||
"lib/browser/api/ipc-main.ts",
|
||||
"lib/browser/api/menu-item-roles.js",
|
||||
"lib/browser/api/menu-item.js",
|
||||
@@ -208,19 +208,19 @@ auto_filenames = {
|
||||
"lib/browser/api/native-theme.ts",
|
||||
"lib/browser/api/net-log.js",
|
||||
"lib/browser/api/net.ts",
|
||||
"lib/browser/api/notification.js",
|
||||
"lib/browser/api/notification.ts",
|
||||
"lib/browser/api/power-monitor.ts",
|
||||
"lib/browser/api/power-save-blocker.js",
|
||||
"lib/browser/api/power-save-blocker.ts",
|
||||
"lib/browser/api/protocol.ts",
|
||||
"lib/browser/api/screen.ts",
|
||||
"lib/browser/api/session.js",
|
||||
"lib/browser/api/session.ts",
|
||||
"lib/browser/api/system-preferences.ts",
|
||||
"lib/browser/api/top-level-window.js",
|
||||
"lib/browser/api/touch-bar.js",
|
||||
"lib/browser/api/tray.js",
|
||||
"lib/browser/api/view.js",
|
||||
"lib/browser/api/views/image-view.js",
|
||||
"lib/browser/api/web-contents-view.js",
|
||||
"lib/browser/api/tray.ts",
|
||||
"lib/browser/api/view.ts",
|
||||
"lib/browser/api/views/image-view.ts",
|
||||
"lib/browser/api/web-contents-view.ts",
|
||||
"lib/browser/api/web-contents.js",
|
||||
"lib/browser/chrome-extension-shim.js",
|
||||
"lib/browser/default-menu.ts",
|
||||
@@ -238,11 +238,11 @@ auto_filenames = {
|
||||
"lib/browser/remote/server.ts",
|
||||
"lib/browser/rpc-server.js",
|
||||
"lib/browser/utils.ts",
|
||||
"lib/common/api/clipboard.js",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/init.ts",
|
||||
@@ -260,11 +260,11 @@ auto_filenames = {
|
||||
|
||||
renderer_bundle_deps = [
|
||||
"lib/browser/api/module-names.ts",
|
||||
"lib/common/api/clipboard.js",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/init.ts",
|
||||
@@ -302,11 +302,11 @@ auto_filenames = {
|
||||
|
||||
worker_bundle_deps = [
|
||||
"lib/browser/api/module-names.ts",
|
||||
"lib/common/api/clipboard.js",
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.js",
|
||||
"lib/common/api/shell.js",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/electron-binding-setup.ts",
|
||||
"lib/common/init.ts",
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
'use strict';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
const { EventEmitter } = require('events');
|
||||
const { BrowserView } = process.electronBinding('browser_view');
|
||||
|
||||
Object.setPrototypeOf(BrowserView.prototype, EventEmitter.prototype);
|
||||
|
||||
BrowserView.fromWebContents = (webContents) => {
|
||||
BrowserView.fromWebContents = (webContents: Electron.WebContents) => {
|
||||
for (const view of BrowserView.getAllViews()) {
|
||||
if (view.webContents.equal(webContents)) return view;
|
||||
}
|
||||
@@ -13,4 +12,4 @@ BrowserView.fromWebContents = (webContents) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
module.exports = BrowserView;
|
||||
export default BrowserView;
|
||||
@@ -1,2 +0,0 @@
|
||||
'use strict';
|
||||
module.exports = process.electronBinding('content_tracing');
|
||||
1
lib/browser/api/content-tracing.ts
Normal file
1
lib/browser/api/content-tracing.ts
Normal file
@@ -0,0 +1 @@
|
||||
export default process.electronBinding('content_tracing');
|
||||
@@ -1,3 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = process.electronBinding('global_shortcut').globalShortcut;
|
||||
1
lib/browser/api/global-shortcut.ts
Normal file
1
lib/browser/api/global-shortcut.ts
Normal file
@@ -0,0 +1 @@
|
||||
export default process.electronBinding('global_shortcut').globalShortcut;
|
||||
@@ -1,22 +1,24 @@
|
||||
'use strict';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
const { deprecate } = require('electron');
|
||||
let _inAppPurchase;
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
const { EventEmitter } = require('events');
|
||||
const { inAppPurchase, InAppPurchase } = process.electronBinding('in_app_purchase');
|
||||
|
||||
// inAppPurchase is an EventEmitter.
|
||||
Object.setPrototypeOf(InAppPurchase.prototype, EventEmitter.prototype);
|
||||
EventEmitter.call(inAppPurchase);
|
||||
|
||||
module.exports = inAppPurchase;
|
||||
_inAppPurchase = inAppPurchase;
|
||||
} else {
|
||||
module.exports = {
|
||||
purchaseProduct: (productID, quantity, callback) => {
|
||||
_inAppPurchase = new EventEmitter();
|
||||
Object.assign(_inAppPurchase, {
|
||||
purchaseProduct: () => {
|
||||
throw new Error('The inAppPurchase module can only be used on macOS');
|
||||
},
|
||||
canMakePayments: () => false,
|
||||
getReceiptURL: () => ''
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default _inAppPurchase;
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const { Notification, isSupported } = process.electronBinding('notification');
|
||||
|
||||
Notification.isSupported = isSupported;
|
||||
|
||||
module.exports = Notification;
|
||||
5
lib/browser/api/notification.ts
Normal file
5
lib/browser/api/notification.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
const { Notification: ElectronNotification, isSupported } = process.electronBinding('notification');
|
||||
|
||||
ElectronNotification.isSupported = isSupported;
|
||||
|
||||
export default ElectronNotification;
|
||||
@@ -1,3 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = process.electronBinding('power_save_blocker').powerSaveBlocker;
|
||||
1
lib/browser/api/power-save-blocker.ts
Normal file
1
lib/browser/api/power-save-blocker.ts
Normal file
@@ -0,0 +1 @@
|
||||
export default process.electronBinding('power_save_blocker').powerSaveBlocker;
|
||||
@@ -1,17 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const { EventEmitter } = require('events');
|
||||
const { app, deprecate } = require('electron');
|
||||
const { fromPartition } = process.electronBinding('session');
|
||||
|
||||
// Public API.
|
||||
Object.defineProperties(exports, {
|
||||
defaultSession: {
|
||||
enumerable: true,
|
||||
get () { return fromPartition(''); }
|
||||
},
|
||||
fromPartition: {
|
||||
enumerable: true,
|
||||
value: fromPartition
|
||||
}
|
||||
});
|
||||
8
lib/browser/api/session.ts
Normal file
8
lib/browser/api/session.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
const { fromPartition } = process.electronBinding('session');
|
||||
|
||||
export default {
|
||||
fromPartition,
|
||||
get defaultSession () {
|
||||
return fromPartition('');
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
const { Tray } = process.electronBinding('tray');
|
||||
|
||||
module.exports = Tray;
|
||||
export default Tray;
|
||||
@@ -1,5 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
const { View } = process.electronBinding('view');
|
||||
|
||||
module.exports = View;
|
||||
export default View;
|
||||
@@ -1,8 +1,7 @@
|
||||
const electron = require('electron');
|
||||
import { View } from 'electron';
|
||||
|
||||
const { View } = electron;
|
||||
const { ImageView } = process.electronBinding('image_view');
|
||||
|
||||
Object.setPrototypeOf(ImageView.prototype, View.prototype);
|
||||
|
||||
module.exports = ImageView;
|
||||
export default ImageView;
|
||||
@@ -1,10 +1,7 @@
|
||||
'use strict';
|
||||
import { View } from 'electron';
|
||||
|
||||
const electron = require('electron');
|
||||
|
||||
const { View } = electron;
|
||||
const { WebContentsView } = process.electronBinding('web_contents_view');
|
||||
|
||||
Object.setPrototypeOf(WebContentsView.prototype, View.prototype);
|
||||
|
||||
module.exports = WebContentsView;
|
||||
export default WebContentsView;
|
||||
@@ -4,13 +4,12 @@ import * as electron from 'electron';
|
||||
import { EventEmitter } from 'events';
|
||||
import objectsRegistry from './objects-registry';
|
||||
import { ipcMainInternal } from '../ipc-main-internal';
|
||||
import { isPromise, isSerializableObject, deserialize, serialize } from '@electron/internal/common/type-utils';
|
||||
import { isPromise, isSerializableObject, deserialize } from '@electron/internal/common/type-utils';
|
||||
import { Size } from 'electron/main';
|
||||
|
||||
const v8Util = process.electronBinding('v8_util');
|
||||
const eventBinding = process.electronBinding('event');
|
||||
const features = process.electronBinding('features');
|
||||
const { NativeImage } = process.electronBinding('native_image');
|
||||
|
||||
if (!features.isRemoteModuleEnabled()) {
|
||||
throw new Error('remote module is disabled');
|
||||
@@ -115,9 +114,6 @@ type MetaType = {
|
||||
} | {
|
||||
type: 'promise',
|
||||
then: MetaType
|
||||
} | {
|
||||
type: 'nativeimage'
|
||||
value: electron.NativeImage
|
||||
}
|
||||
|
||||
// Convert a real value into meta data.
|
||||
@@ -128,8 +124,6 @@ const valueToMeta = function (sender: electron.WebContents, contextId: string, v
|
||||
// Recognize certain types of objects.
|
||||
if (value instanceof Buffer) {
|
||||
type = 'buffer';
|
||||
} else if (value instanceof NativeImage) {
|
||||
type = 'nativeimage';
|
||||
} else if (Array.isArray(value)) {
|
||||
type = 'array';
|
||||
} else if (value instanceof Error) {
|
||||
@@ -153,8 +147,6 @@ const valueToMeta = function (sender: electron.WebContents, contextId: string, v
|
||||
type,
|
||||
members: value.map((el: any) => valueToMeta(sender, contextId, el, optimizeSimpleObject))
|
||||
};
|
||||
} else if (type === 'nativeimage') {
|
||||
return { type, value: serialize(value) };
|
||||
} else if (type === 'object' || type === 'function') {
|
||||
return {
|
||||
type,
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const clipboard = process.electronBinding('clipboard');
|
||||
|
||||
if (process.type === 'renderer') {
|
||||
const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils');
|
||||
const typeUtils = require('@electron/internal/common/type-utils');
|
||||
|
||||
const makeRemoteMethod = function (method) {
|
||||
return (...args) => {
|
||||
const makeRemoteMethod = function (method: keyof Electron.Clipboard) {
|
||||
return (...args: any[]) => {
|
||||
args = typeUtils.serialize(args);
|
||||
const result = ipcRendererUtils.invokeSync('ELECTRON_BROWSER_CLIPBOARD_SYNC', method, ...args);
|
||||
return typeUtils.deserialize(result);
|
||||
@@ -16,7 +14,7 @@ if (process.type === 'renderer') {
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
// On Linux we could not access clipboard in renderer process.
|
||||
for (const method of Object.keys(clipboard)) {
|
||||
for (const method of Object.keys(clipboard) as (keyof Electron.Clipboard)[]) {
|
||||
clipboard[method] = makeRemoteMethod(method);
|
||||
}
|
||||
} else if (process.platform === 'darwin') {
|
||||
@@ -26,4 +24,4 @@ if (process.type === 'renderer') {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = clipboard;
|
||||
export default clipboard;
|
||||
@@ -1,5 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
const { nativeImage } = process.electronBinding('native_image');
|
||||
|
||||
module.exports = nativeImage;
|
||||
export default nativeImage;
|
||||
@@ -1,3 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = process.electronBinding('shell');
|
||||
1
lib/common/api/shell.ts
Normal file
1
lib/common/api/shell.ts
Normal file
@@ -0,0 +1 @@
|
||||
export default process.electronBinding('shell');
|
||||
@@ -5,7 +5,7 @@ const { hasSwitch } = process.electronBinding('command_line');
|
||||
const { NativeImage } = process.electronBinding('native_image');
|
||||
|
||||
const { CallbacksRegistry } = require('@electron/internal/renderer/remote/callbacks-registry');
|
||||
const { isPromise, isSerializableObject, serialize, deserialize } = require('@electron/internal/common/type-utils');
|
||||
const { isPromise, isSerializableObject, serialize } = require('@electron/internal/common/type-utils');
|
||||
const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal');
|
||||
|
||||
const callbacksRegistry = new CallbacksRegistry();
|
||||
@@ -219,7 +219,6 @@ function metaToValue (meta) {
|
||||
const types = {
|
||||
value: () => meta.value,
|
||||
array: () => meta.members.map((member) => metaToValue(member)),
|
||||
nativeimage: () => deserialize(meta.value),
|
||||
buffer: () => Buffer.from(meta.value.buffer, meta.value.byteOffset, meta.value.byteLength),
|
||||
promise: () => Promise.resolve({ then: metaToValue(meta.then) }),
|
||||
error: () => metaToError(meta),
|
||||
|
||||
@@ -84,9 +84,6 @@ const appPath = parseOption('app-path', null);
|
||||
const guestInstanceId = parseOption('guest-instance-id', null, value => parseInt(value));
|
||||
const openerId = parseOption('opener-id', null, value => parseInt(value));
|
||||
|
||||
// The arguments to be passed to isolated world.
|
||||
const isolatedWorldArgs = { ipcRendererInternal, guestInstanceId, isHiddenPage, openerId, usesNativeWindowOpen, rendererProcessReuseEnabled };
|
||||
|
||||
// The webContents preload script is loaded after the session preload scripts.
|
||||
if (preloadScript) {
|
||||
preloadScripts.push(preloadScript);
|
||||
@@ -116,11 +113,6 @@ if (process.isMainFrame) {
|
||||
webViewInit(contextIsolation, webviewTag, guestInstanceId);
|
||||
}
|
||||
|
||||
// Pass the arguments to isolatedWorld.
|
||||
if (contextIsolation) {
|
||||
v8Util.setHiddenValue(global, 'isolated-world-args', isolatedWorldArgs);
|
||||
}
|
||||
|
||||
if (nodeIntegration) {
|
||||
// Export node bindings to global.
|
||||
const { makeRequireFunction } = __non_webpack_require__('internal/modules/cjs/helpers') // eslint-disable-line
|
||||
|
||||
@@ -125,11 +125,7 @@ class LocationProxy {
|
||||
}
|
||||
|
||||
private getGuestURL (): URL | null {
|
||||
const maybeURL = this._invokeWebContentsMethodSync('getURL') as string;
|
||||
|
||||
// When there's no previous frame the url will be blank, so accountfor that here
|
||||
// to prevent url parsing errors on an empty string.
|
||||
const urlString = maybeURL !== '' ? maybeURL : 'about:blank';
|
||||
const urlString = this._invokeWebContentsMethodSync('getURL') as string;
|
||||
try {
|
||||
return new URL(urlString);
|
||||
} catch (e) {
|
||||
|
||||
@@ -124,9 +124,6 @@ const isHiddenPage = hasSwitch('hidden-page');
|
||||
const rendererProcessReuseEnabled = hasSwitch('disable-electron-site-instance-overrides');
|
||||
const usesNativeWindowOpen = true;
|
||||
|
||||
// The arguments to be passed to isolated world.
|
||||
const isolatedWorldArgs = { ipcRendererInternal, guestInstanceId, isHiddenPage, openerId, usesNativeWindowOpen, rendererProcessReuseEnabled };
|
||||
|
||||
switch (window.location.protocol) {
|
||||
case 'devtools:': {
|
||||
// Override some inspector APIs.
|
||||
@@ -152,11 +149,6 @@ if (process.isMainFrame) {
|
||||
webViewInit(contextIsolation, isWebViewTagEnabled, guestInstanceId);
|
||||
}
|
||||
|
||||
// Pass the arguments to isolatedWorld.
|
||||
if (contextIsolation) {
|
||||
v8Util.setHiddenValue(global, 'isolated-world-args', isolatedWorldArgs);
|
||||
}
|
||||
|
||||
// Wrap the script into a function executed in global scope. It won't have
|
||||
// access to the current scope, so we'll expose a few objects as arguments:
|
||||
//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "10.0.0-beta.2",
|
||||
"version": "11.0.0-nightly.20200525",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -3,8 +3,17 @@ From: Jeremy Apthorp <jeremya@chromium.org>
|
||||
Date: Wed, 10 Oct 2018 15:07:34 -0700
|
||||
Subject: command-ismediakey.patch
|
||||
|
||||
Override MediaKeysListener::IsMediaKeycode and associated functions to also listen for
|
||||
Volume Up, Volume Down, and Mute.
|
||||
Override MediaKeysListener::IsMediaKeycode to also listen for Volume Up, Volume Down,
|
||||
and Mute. We also need to patch out Chromium's usage of RemoteCommandCenterDelegate, as
|
||||
it uses MPRemoteCommandCenter. MPRemoteCommandCenter makes it such that GlobalShortcuts
|
||||
in Electron will not work as intended, because by design an app does not receive remote
|
||||
control events until it begins playing audio. This means that a media shortcut would not kick
|
||||
into effect until you, for example, began playing a YouTube video which sort of defeats the
|
||||
purpose of GlobalShortcuts.
|
||||
|
||||
At the moment there is no upstream possibility for this; but perhaps Chromium may
|
||||
consider some kind of switch, enabled by default, which would conditionally choose to avoid usage of
|
||||
RemoteCommandCenterDelegate on macOS.
|
||||
|
||||
Also apply electron/electron@0f67b1866a9f00b852370e721affa4efda623f3a
|
||||
and electron/electron@d2368d2d3b3de9eec4cc32b6aaf035cc89921bf1 as
|
||||
@@ -86,19 +95,3 @@ index 85378bb565de617b1bd611d28c8714361747a357..36de4c0b0353be2418dacd388e92d7c3
|
||||
return event;
|
||||
}
|
||||
|
||||
diff --git a/ui/base/accelerators/system_media_controls_media_keys_listener.cc b/ui/base/accelerators/system_media_controls_media_keys_listener.cc
|
||||
index 9d6084ceaccfd071549e63e3015f55ef292312ec..3f6af8b1b49bf0f226e9336c222884b07bf69e55 100644
|
||||
--- a/ui/base/accelerators/system_media_controls_media_keys_listener.cc
|
||||
+++ b/ui/base/accelerators/system_media_controls_media_keys_listener.cc
|
||||
@@ -65,6 +65,11 @@ bool SystemMediaControlsMediaKeysListener::StartWatchingMediaKey(
|
||||
case VKEY_MEDIA_STOP:
|
||||
service_->SetIsStopEnabled(true);
|
||||
break;
|
||||
+ case VKEY_VOLUME_DOWN:
|
||||
+ case VKEY_VOLUME_UP:
|
||||
+ case VKEY_VOLUME_MUTE:
|
||||
+ // Do nothing.
|
||||
+ break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
@@ -39,6 +39,12 @@ class GHKey {
|
||||
this.repo = repo;
|
||||
this.number = number;
|
||||
}
|
||||
static NewFromPull (pull) {
|
||||
const owner = pull.base.repo.owner.login;
|
||||
const repo = pull.base.repo.name;
|
||||
const number = pull.number;
|
||||
return new GHKey(owner, repo, number);
|
||||
}
|
||||
}
|
||||
|
||||
class Commit {
|
||||
@@ -289,9 +295,33 @@ async function runRetryable (fn, maxRetries) {
|
||||
if (lastError.status !== 404) throw lastError;
|
||||
}
|
||||
|
||||
const getPullCacheFilename = ghKey => `${ghKey.owner}-${ghKey.repo}-pull-${ghKey.number}`;
|
||||
|
||||
const getCommitPulls = async (owner, repo, hash) => {
|
||||
const name = `${owner}-${repo}-commit-${hash}`;
|
||||
const retryableFunc = () => octokit.repos.listPullRequestsAssociatedWithCommit({ owner, repo, commit_sha: hash });
|
||||
const ret = await checkCache(name, () => runRetryable(retryableFunc, MAX_FAIL_COUNT));
|
||||
|
||||
// only merged pulls belong in release notes
|
||||
if (ret && ret.data) {
|
||||
ret.data = ret.data.filter(pull => pull.merged_at);
|
||||
}
|
||||
|
||||
// cache the pulls
|
||||
if (ret && ret.data) {
|
||||
for (const pull of ret.data) {
|
||||
const cachefile = getPullCacheFilename(GHKey.NewFromPull(pull));
|
||||
const payload = { ...ret, data: pull };
|
||||
await checkCache(cachefile, () => payload);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
const getPullRequest = async (ghKey) => {
|
||||
const { number, owner, repo } = ghKey;
|
||||
const name = `${owner}-${repo}-pull-${number}`;
|
||||
const name = getPullCacheFilename(ghKey);
|
||||
const retryableFunc = () => octokit.pulls.get({ pull_number: number, owner, repo });
|
||||
return checkCache(name, () => runRetryable(retryableFunc, MAX_FAIL_COUNT));
|
||||
};
|
||||
@@ -306,10 +336,20 @@ const getComments = async (ghKey) => {
|
||||
const addRepoToPool = async (pool, repo, from, to) => {
|
||||
const commonAncestor = await getCommonAncestor(repo.dir, from, to);
|
||||
|
||||
// add the commits
|
||||
const oldHashes = await getLocalCommitHashes(repo.dir, from);
|
||||
oldHashes.forEach(hash => { pool.processedHashes.add(hash); });
|
||||
// mark the old branch's commits as old news
|
||||
for (const oldHash of await getLocalCommitHashes(repo.dir, from)) {
|
||||
pool.processedHashes.add(oldHash);
|
||||
}
|
||||
|
||||
// get the new branch's commits and the pulls associated with them
|
||||
const commits = await getLocalCommits(repo, commonAncestor, to);
|
||||
for (const commit of commits) {
|
||||
const { owner, repo, hash } = commit;
|
||||
for (const pull of (await getCommitPulls(owner, repo, hash)).data) {
|
||||
commit.prKeys.add(GHKey.NewFromPull(pull));
|
||||
}
|
||||
}
|
||||
|
||||
pool.commits.push(...commits);
|
||||
|
||||
// add the pulls
|
||||
@@ -317,8 +357,7 @@ const addRepoToPool = async (pool, repo, from, to) => {
|
||||
let prKey;
|
||||
for (prKey of commit.prKeys.values()) {
|
||||
const pull = await getPullRequest(prKey);
|
||||
if (!pull || !pull.data) break; // couldn't get it
|
||||
if (pool.pulls[prKey.number]) break; // already have it
|
||||
if (!pull || !pull.data) continue; // couldn't get it
|
||||
pool.pulls[prKey.number] = pull;
|
||||
parsePullText(pull, commit);
|
||||
}
|
||||
|
||||
@@ -266,9 +266,6 @@ void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) {
|
||||
// Already closed by renderer
|
||||
return;
|
||||
|
||||
// Required to make beforeunload handler work.
|
||||
api_web_contents_->NotifyUserActivation();
|
||||
|
||||
if (web_contents()->NeedToFireBeforeUnloadOrUnload())
|
||||
web_contents()->DispatchBeforeUnload(false /* auto_cancel */);
|
||||
else
|
||||
|
||||
@@ -29,9 +29,7 @@ bool RegisteringMediaKeyForUntrustedClient(const ui::Accelerator& accelerator) {
|
||||
if (base::mac::IsAtLeastOS10_14()) {
|
||||
constexpr ui::KeyboardCode mediaKeys[] = {
|
||||
ui::VKEY_MEDIA_PLAY_PAUSE, ui::VKEY_MEDIA_NEXT_TRACK,
|
||||
ui::VKEY_MEDIA_PREV_TRACK, ui::VKEY_MEDIA_STOP,
|
||||
ui::VKEY_VOLUME_UP, ui::VKEY_VOLUME_DOWN,
|
||||
ui::VKEY_VOLUME_MUTE};
|
||||
ui::VKEY_MEDIA_PREV_TRACK, ui::VKEY_MEDIA_STOP};
|
||||
|
||||
if (std::find(std::begin(mediaKeys), std::end(mediaKeys),
|
||||
accelerator.key_code()) != std::end(mediaKeys)) {
|
||||
@@ -62,7 +60,7 @@ GlobalShortcut::~GlobalShortcut() {
|
||||
void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
|
||||
if (accelerator_callback_map_.find(accelerator) ==
|
||||
accelerator_callback_map_.end()) {
|
||||
// This should never occur, because if it does, GlobalShortcutListener
|
||||
// This should never occur, because if it does, GlobalGlobalShortcutListener
|
||||
// notifies us with wrong accelerator.
|
||||
NOTREACHED();
|
||||
return;
|
||||
|
||||
@@ -756,8 +756,6 @@ void WebContents::BeforeUnloadFired(content::WebContents* tab,
|
||||
*proceed_to_fire_unload = proceed;
|
||||
else
|
||||
*proceed_to_fire_unload = true;
|
||||
// Note that Chromium does not emit this for navigations.
|
||||
Emit("before-unload-fired", proceed);
|
||||
}
|
||||
|
||||
void WebContents::SetContentsBounds(content::WebContents* source,
|
||||
@@ -1548,9 +1546,6 @@ void WebContents::LoadURL(const GURL& url,
|
||||
// Calling LoadURLWithParams() can trigger JS which destroys |this|.
|
||||
auto weak_this = GetWeakPtr();
|
||||
|
||||
// Required to make beforeunload handler work.
|
||||
NotifyUserActivation();
|
||||
|
||||
params.transition_type = ui::PAGE_TRANSITION_TYPED;
|
||||
params.should_clear_history_list = true;
|
||||
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
|
||||
@@ -2680,15 +2675,6 @@ void WebContents::GrantOriginAccess(const GURL& url) {
|
||||
url::Origin::Create(url));
|
||||
}
|
||||
|
||||
void WebContents::NotifyUserActivation() {
|
||||
auto* frame = web_contents()->GetMainFrame();
|
||||
if (!frame)
|
||||
return;
|
||||
mojo::AssociatedRemote<mojom::ElectronRenderer> renderer;
|
||||
frame->GetRemoteAssociatedInterfaces()->GetInterface(&renderer);
|
||||
renderer->NotifyUserActivation();
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> WebContents::TakeHeapSnapshot(
|
||||
const base::FilePath& file_path) {
|
||||
gin_helper::Promise<void> promise(isolate());
|
||||
|
||||
@@ -367,9 +367,6 @@ class WebContents : public gin_helper::TrackableObject<WebContents>,
|
||||
// the specified URL.
|
||||
void GrantOriginAccess(const GURL& url);
|
||||
|
||||
// Notifies the web page that there is user interaction.
|
||||
void NotifyUserActivation();
|
||||
|
||||
v8::Local<v8::Promise> TakeHeapSnapshot(const base::FilePath& file_path);
|
||||
|
||||
// Properties.
|
||||
|
||||
@@ -1454,27 +1454,25 @@ void NativeWindowMac::SetVibrancy(const std::string& type) {
|
||||
[effect_view setState:NSVisualEffectStateActive];
|
||||
|
||||
// Make frameless Vibrant windows have rounded corners.
|
||||
if (!has_frame()) {
|
||||
CGFloat radius = 5.0f; // default corner radius
|
||||
CGFloat dimension = 2 * radius + 1;
|
||||
NSSize size = NSMakeSize(dimension, dimension);
|
||||
NSImage* maskImage = [NSImage imageWithSize:size
|
||||
flipped:NO
|
||||
drawingHandler:^BOOL(NSRect rect) {
|
||||
NSBezierPath* bezierPath = [NSBezierPath
|
||||
bezierPathWithRoundedRect:rect
|
||||
xRadius:radius
|
||||
yRadius:radius];
|
||||
[[NSColor blackColor] set];
|
||||
[bezierPath fill];
|
||||
return YES;
|
||||
}];
|
||||
[maskImage setCapInsets:NSEdgeInsetsMake(radius, radius, radius, radius)];
|
||||
[maskImage setResizingMode:NSImageResizingModeStretch];
|
||||
CGFloat radius = 5.0f; // default corner radius
|
||||
CGFloat dimension = 2 * radius + 1;
|
||||
NSSize size = NSMakeSize(dimension, dimension);
|
||||
NSImage* maskImage = [NSImage imageWithSize:size
|
||||
flipped:NO
|
||||
drawingHandler:^BOOL(NSRect rect) {
|
||||
NSBezierPath* bezierPath = [NSBezierPath
|
||||
bezierPathWithRoundedRect:rect
|
||||
xRadius:radius
|
||||
yRadius:radius];
|
||||
[[NSColor blackColor] set];
|
||||
[bezierPath fill];
|
||||
return YES;
|
||||
}];
|
||||
[maskImage setCapInsets:NSEdgeInsetsMake(radius, radius, radius, radius)];
|
||||
[maskImage setResizingMode:NSImageResizingModeStretch];
|
||||
|
||||
[effect_view setMaskImage:maskImage];
|
||||
[window_ setCornerMask:maskImage];
|
||||
}
|
||||
[effect_view setMaskImage:maskImage];
|
||||
[window_ setCornerMask:maskImage];
|
||||
|
||||
[[window_ contentView] addSubview:effect_view
|
||||
positioned:NSWindowBelow
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 10,0,0,2
|
||||
PRODUCTVERSION 10,0,0,2
|
||||
FILEVERSION 11,0,0,20200525
|
||||
PRODUCTVERSION 11,0,0,20200525
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -68,12 +68,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "10.0.0"
|
||||
VALUE "FileVersion", "11.0.0"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "10.0.0"
|
||||
VALUE "ProductVersion", "11.0.0"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
namespace electron {
|
||||
@@ -25,13 +24,15 @@ class ElectronMenuModel;
|
||||
// as it only maintains weak references.
|
||||
@interface ElectronMenuController : NSObject <NSMenuDelegate> {
|
||||
@protected
|
||||
base::WeakPtr<electron::ElectronMenuModel> model_;
|
||||
electron::ElectronMenuModel* model_; // weak
|
||||
base::scoped_nsobject<NSMenu> menu_;
|
||||
BOOL isMenuOpen_;
|
||||
BOOL useDefaultAccelerator_;
|
||||
base::OnceClosure closeCallback;
|
||||
}
|
||||
|
||||
@property(nonatomic, assign) electron::ElectronMenuModel* model;
|
||||
|
||||
// Builds a NSMenu from the pre-built model (must not be nil). Changes made
|
||||
// to the contents of the model after calling this will not be noticed.
|
||||
- (id)initWithModel:(electron::ElectronMenuModel*)model
|
||||
@@ -45,9 +46,6 @@ class ElectronMenuModel;
|
||||
// Programmatically close the constructed menu.
|
||||
- (void)cancel;
|
||||
|
||||
- (electron::ElectronMenuModel*)model;
|
||||
- (void)setModel:(electron::ElectronMenuModel*)model;
|
||||
|
||||
// Access to the constructed menu if the complex initializer was used. If the
|
||||
// default initializer was used, then this will create the menu on first call.
|
||||
- (NSMenu*)menu;
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/mac/foundation_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task/post_task.h"
|
||||
@@ -88,44 +87,6 @@ NSMenu* MakeEmptySubmenu() {
|
||||
|
||||
} // namespace
|
||||
|
||||
// This class stores a base::WeakPtr<electron::ElectronMenuModel> as an
|
||||
// Objective-C object, which allows it to be stored in the representedObject
|
||||
// field of an NSMenuItem.
|
||||
@interface WeakPtrToElectronMenuModelAsNSObject : NSObject
|
||||
+ (instancetype)weakPtrForModel:(electron::ElectronMenuModel*)model;
|
||||
+ (electron::ElectronMenuModel*)getFrom:(id)instance;
|
||||
- (instancetype)initWithModel:(electron::ElectronMenuModel*)model;
|
||||
- (electron::ElectronMenuModel*)menuModel;
|
||||
@end
|
||||
|
||||
@implementation WeakPtrToElectronMenuModelAsNSObject {
|
||||
base::WeakPtr<electron::ElectronMenuModel> _model;
|
||||
}
|
||||
|
||||
+ (instancetype)weakPtrForModel:(electron::ElectronMenuModel*)model {
|
||||
return [[[WeakPtrToElectronMenuModelAsNSObject alloc] initWithModel:model]
|
||||
autorelease];
|
||||
}
|
||||
|
||||
+ (electron::ElectronMenuModel*)getFrom:(id)instance {
|
||||
return
|
||||
[base::mac::ObjCCastStrict<WeakPtrToElectronMenuModelAsNSObject>(instance)
|
||||
menuModel];
|
||||
}
|
||||
|
||||
- (instancetype)initWithModel:(electron::ElectronMenuModel*)model {
|
||||
if ((self = [super init])) {
|
||||
_model = model->GetWeakPtr();
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (electron::ElectronMenuModel*)menuModel {
|
||||
return _model.get();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// Menu item is located for ease of removing it from the parent owner
|
||||
static base::scoped_nsobject<NSMenuItem> recentDocumentsMenuItem_;
|
||||
|
||||
@@ -134,18 +95,12 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
||||
|
||||
@implementation ElectronMenuController
|
||||
|
||||
- (electron::ElectronMenuModel*)model {
|
||||
return model_.get();
|
||||
}
|
||||
@synthesize model = model_;
|
||||
|
||||
- (void)setModel:(electron::ElectronMenuModel*)model {
|
||||
model_ = model->GetWeakPtr();
|
||||
}
|
||||
|
||||
- (instancetype)initWithModel:(electron::ElectronMenuModel*)model
|
||||
useDefaultAccelerator:(BOOL)use {
|
||||
- (id)initWithModel:(electron::ElectronMenuModel*)model
|
||||
useDefaultAccelerator:(BOOL)use {
|
||||
if ((self = [super init])) {
|
||||
model_ = model->GetWeakPtr();
|
||||
model_ = model;
|
||||
isMenuOpen_ = NO;
|
||||
useDefaultAccelerator_ = use;
|
||||
[self menu];
|
||||
@@ -160,7 +115,8 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
||||
// while its context menu is still open.
|
||||
[self cancel];
|
||||
|
||||
model_ = nullptr;
|
||||
model_ = nil;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -181,7 +137,7 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
||||
itemWithTitle:@"Electron"] submenu] itemWithTitle:openTitle] retain]);
|
||||
}
|
||||
|
||||
model_ = model->GetWeakPtr();
|
||||
model_ = model;
|
||||
[menu_ removeAllItems];
|
||||
|
||||
const int count = model->GetItemCount();
|
||||
@@ -197,8 +153,7 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
||||
if (isMenuOpen_) {
|
||||
[menu_ cancelTracking];
|
||||
isMenuOpen_ = NO;
|
||||
if (model_)
|
||||
model_->MenuWillClose();
|
||||
model_->MenuWillClose();
|
||||
if (!closeCallback.is_null()) {
|
||||
base::PostTask(FROM_HERE, {BrowserThread::UI}, std::move(closeCallback));
|
||||
}
|
||||
@@ -335,8 +290,8 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
||||
// model. Setting the target to |self| allows this class to participate
|
||||
// in validation of the menu items.
|
||||
[item setTag:index];
|
||||
[item setRepresentedObject:[WeakPtrToElectronMenuModelAsNSObject
|
||||
weakPtrForModel:model]];
|
||||
NSValue* modelObject = [NSValue valueWithPointer:model];
|
||||
[item setRepresentedObject:modelObject]; // Retains |modelObject|.
|
||||
ui::Accelerator accelerator;
|
||||
if (model->GetAcceleratorAtWithParams(index, useDefaultAccelerator_,
|
||||
&accelerator)) {
|
||||
@@ -376,8 +331,9 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
||||
return NO;
|
||||
|
||||
NSInteger modelIndex = [item tag];
|
||||
electron::ElectronMenuModel* model = [WeakPtrToElectronMenuModelAsNSObject
|
||||
getFrom:[(id)item representedObject]];
|
||||
electron::ElectronMenuModel* model =
|
||||
static_cast<electron::ElectronMenuModel*>(
|
||||
[[(id)item representedObject] pointerValue]);
|
||||
DCHECK(model);
|
||||
if (model) {
|
||||
BOOL checked = model->IsItemCheckedAt(modelIndex);
|
||||
@@ -396,7 +352,8 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
||||
- (void)itemSelected:(id)sender {
|
||||
NSInteger modelIndex = [sender tag];
|
||||
electron::ElectronMenuModel* model =
|
||||
[WeakPtrToElectronMenuModelAsNSObject getFrom:[sender representedObject]];
|
||||
static_cast<electron::ElectronMenuModel*>(
|
||||
[[sender representedObject] pointerValue]);
|
||||
DCHECK(model);
|
||||
if (model) {
|
||||
NSEvent* event = [NSApp currentEvent];
|
||||
@@ -412,7 +369,7 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
||||
menu_.reset([[NSMenu alloc] initWithTitle:@""]);
|
||||
[menu_ setDelegate:self];
|
||||
if (model_)
|
||||
[self populateWithModel:model_.get()];
|
||||
[self populateWithModel:model_];
|
||||
return menu_.get();
|
||||
}
|
||||
|
||||
@@ -422,8 +379,7 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
|
||||
|
||||
- (void)menuWillOpen:(NSMenu*)menu {
|
||||
isMenuOpen_ = YES;
|
||||
if (model_)
|
||||
model_->MenuWillShow();
|
||||
model_->MenuWillShow();
|
||||
}
|
||||
|
||||
- (void)menuDidClose:(NSMenu*)menu {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/observer_list_types.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
@@ -70,10 +69,6 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
|
||||
void MenuWillClose() override;
|
||||
void MenuWillShow() override;
|
||||
|
||||
base::WeakPtr<ElectronMenuModel> GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
using SimpleMenuModel::GetSubmenuModelAt;
|
||||
ElectronMenuModel* GetSubmenuModelAt(int index);
|
||||
|
||||
@@ -85,8 +80,6 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
|
||||
std::map<int, base::string16> sublabels_; // command id -> sublabel
|
||||
base::ObserverList<Observer> observers_;
|
||||
|
||||
base::WeakPtrFactory<ElectronMenuModel> weak_factory_{this};
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ElectronMenuModel);
|
||||
};
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ interface ElectronRenderer {
|
||||
string context_id,
|
||||
int32 object_id);
|
||||
|
||||
NotifyUserActivation();
|
||||
|
||||
TakeHeapSnapshot(handle file) => (bool success);
|
||||
};
|
||||
|
||||
|
||||
@@ -93,8 +93,8 @@ bool IsRunningInDesktopBridgeImpl() {
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 length = PACKAGE_FAMILY_NAME_MAX_LENGTH;
|
||||
wchar_t packageFamilyName[PACKAGE_FAMILY_NAME_MAX_LENGTH];
|
||||
UINT32 length;
|
||||
wchar_t packageFamilyName[PACKAGE_FAMILY_NAME_MAX_LENGTH + 1];
|
||||
HANDLE proc = GetCurrentProcess();
|
||||
LONG result =
|
||||
(*get_package_family_namePtr)(proc, &length, packageFamilyName);
|
||||
|
||||
@@ -236,12 +236,6 @@ void ElectronApiServiceImpl::DereferenceRemoteJSCallback(
|
||||
}
|
||||
#endif
|
||||
|
||||
void ElectronApiServiceImpl::NotifyUserActivation() {
|
||||
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
|
||||
if (frame)
|
||||
frame->NotifyUserActivation();
|
||||
}
|
||||
|
||||
void ElectronApiServiceImpl::TakeHeapSnapshot(
|
||||
mojo::ScopedHandle file,
|
||||
TakeHeapSnapshotCallback callback) {
|
||||
|
||||
@@ -39,7 +39,6 @@ class ElectronApiServiceImpl : public mojom::ElectronRenderer,
|
||||
void DereferenceRemoteJSCallback(const std::string& context_id,
|
||||
int32_t object_id) override;
|
||||
#endif
|
||||
void NotifyUserActivation() override;
|
||||
void TakeHeapSnapshot(mojo::ScopedHandle file,
|
||||
TakeHeapSnapshotCallback callback) override;
|
||||
|
||||
|
||||
1
spec-main/ambient.d.ts
vendored
1
spec-main/ambient.d.ts
vendored
@@ -25,7 +25,6 @@ declare namespace Electron {
|
||||
constructor(args: {show: boolean})
|
||||
setContentView(view: View): void
|
||||
}
|
||||
class View {}
|
||||
class WebContentsView {
|
||||
constructor(options: BrowserWindowConstructorOptions)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as http from 'http';
|
||||
import { AddressInfo } from 'net';
|
||||
import { app, BrowserWindow, BrowserView, ipcMain, OnBeforeSendHeadersListenerDetails, protocol, screen, webContents, session, WebContents } from 'electron/main';
|
||||
|
||||
import { emittedOnce, emittedUntil } from './events-helpers';
|
||||
import { emittedOnce } from './events-helpers';
|
||||
import { ifit, ifdescribe } from './spec-helpers';
|
||||
import { closeWindow, closeAllWindows } from './window-helpers';
|
||||
|
||||
@@ -38,10 +38,6 @@ const expectBoundsEqual = (actual: any, expected: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
const isBeforeUnload = (event: Event, level: number, message: string) => {
|
||||
return (message === 'beforeunload');
|
||||
};
|
||||
|
||||
describe('BrowserWindow module', () => {
|
||||
describe('BrowserWindow constructor', () => {
|
||||
it('allows passing void 0 as the webContents', async () => {
|
||||
@@ -99,11 +95,16 @@ describe('BrowserWindow module', () => {
|
||||
fs.unlinkSync(test);
|
||||
expect(String(content)).to.equal('unload');
|
||||
});
|
||||
|
||||
it('should emit beforeunload handler', async () => {
|
||||
await w.loadFile(path.join(fixtures, 'api', 'beforeunload-false.html'));
|
||||
const beforeunload = new Promise(resolve => {
|
||||
ipcMain.once('onbeforeunload', (e) => {
|
||||
e.returnValue = null;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
w.close();
|
||||
await emittedOnce(w.webContents, 'before-unload-fired');
|
||||
await beforeunload;
|
||||
});
|
||||
|
||||
describe('when invoked synchronously inside navigation observer', () => {
|
||||
@@ -184,11 +185,13 @@ describe('BrowserWindow module', () => {
|
||||
fs.unlinkSync(test);
|
||||
expect(content).to.equal('close');
|
||||
});
|
||||
|
||||
it('should emit beforeunload event', async function () {
|
||||
// TODO(nornagon): deflake this test.
|
||||
this.retries(3);
|
||||
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-false.html'));
|
||||
w.webContents.executeJavaScript('window.close()', true);
|
||||
await emittedOnce(w.webContents, 'before-unload-fired');
|
||||
w.webContents.executeJavaScript('run()', true);
|
||||
const [e] = await emittedOnce(ipcMain, 'onbeforeunload');
|
||||
e.returnValue = null;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2626,31 +2629,32 @@ describe('BrowserWindow module', () => {
|
||||
});
|
||||
|
||||
describe('beforeunload handler', function () {
|
||||
// TODO(nornagon): I feel like these tests _oughtn't_ be flakey, but
|
||||
// beforeunload is in general not reliable on the web, so i'm not going to
|
||||
// worry about it too much for now.
|
||||
this.retries(3);
|
||||
|
||||
let w: BrowserWindow = null as unknown as BrowserWindow;
|
||||
beforeEach(() => {
|
||||
w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
|
||||
});
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
it('returning undefined would not prevent close', async () => {
|
||||
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-undefined.html'));
|
||||
const wait = emittedOnce(w, 'closed');
|
||||
w.close();
|
||||
await wait;
|
||||
afterEach(() => {
|
||||
ipcMain.removeAllListeners('onbeforeunload');
|
||||
});
|
||||
afterEach(closeAllWindows);
|
||||
it('returning undefined would not prevent close', (done) => {
|
||||
w.once('closed', () => { done(); });
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-undefined.html'));
|
||||
});
|
||||
|
||||
it('returning false would prevent close', async () => {
|
||||
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-false.html'));
|
||||
w.close();
|
||||
const [, proceed] = await emittedOnce(w.webContents, 'before-unload-fired');
|
||||
expect(proceed).to.equal(false);
|
||||
w.webContents.executeJavaScript('run()', true);
|
||||
const [e] = await emittedOnce(ipcMain, 'onbeforeunload');
|
||||
e.returnValue = null;
|
||||
});
|
||||
|
||||
it('returning empty string would prevent close', async () => {
|
||||
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-empty-string.html'));
|
||||
w.close();
|
||||
const [, proceed] = await emittedOnce(w.webContents, 'before-unload-fired');
|
||||
expect(proceed).to.equal(false);
|
||||
it('returning empty string would prevent close', (done) => {
|
||||
ipcMain.once('onbeforeunload', (e) => { e.returnValue = null; done(); });
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-empty-string.html'));
|
||||
});
|
||||
|
||||
it('emits for each close attempt', async () => {
|
||||
@@ -2659,16 +2663,46 @@ describe('BrowserWindow module', () => {
|
||||
const destroyListener = () => { expect.fail('Close was not prevented'); };
|
||||
w.webContents.once('destroyed', destroyListener);
|
||||
|
||||
await w.webContents.executeJavaScript('installBeforeUnload(2)', true);
|
||||
w.close();
|
||||
await emittedOnce(w.webContents, 'before-unload-fired');
|
||||
w.close();
|
||||
await emittedOnce(w.webContents, 'before-unload-fired');
|
||||
await w.webContents.executeJavaScript('preventNextBeforeUnload()', true);
|
||||
{
|
||||
const p = emittedOnce(ipcMain, 'onbeforeunload');
|
||||
w.close();
|
||||
const [e] = await p;
|
||||
e.returnValue = null;
|
||||
}
|
||||
|
||||
await w.webContents.executeJavaScript('preventNextBeforeUnload()', true);
|
||||
|
||||
// Hi future test refactorer! I don't know what event this timeout allows
|
||||
// to occur, but without it, this test becomes flaky at this point and
|
||||
// sometimes the window gets closed even though a `beforeunload` handler
|
||||
// has been installed. I looked for events being emitted by the
|
||||
// `webContents` during this timeout period and found nothing, so it
|
||||
// might be some sort of internal timeout being applied by the content/
|
||||
// layer, or blink?
|
||||
//
|
||||
// In any case, this incantation reduces flakiness. I'm going to add a
|
||||
// summoning circle for good measure.
|
||||
//
|
||||
// 🕯 🕯
|
||||
// 🕯 🕯
|
||||
// 🕯 🕯
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
// 🕯 🕯
|
||||
// 🕯 🕯
|
||||
// 🕯 🕯
|
||||
|
||||
{
|
||||
const p = emittedOnce(ipcMain, 'onbeforeunload');
|
||||
w.close();
|
||||
const [e] = await p;
|
||||
e.returnValue = null;
|
||||
}
|
||||
|
||||
w.webContents.removeListener('destroyed', destroyListener);
|
||||
const wait = emittedOnce(w, 'closed');
|
||||
const p = emittedOnce(w.webContents, 'destroyed');
|
||||
w.close();
|
||||
await wait;
|
||||
await p;
|
||||
});
|
||||
|
||||
it('emits for each reload attempt', async () => {
|
||||
@@ -2677,14 +2711,19 @@ describe('BrowserWindow module', () => {
|
||||
const navigationListener = () => { expect.fail('Reload was not prevented'); };
|
||||
w.webContents.once('did-start-navigation', navigationListener);
|
||||
|
||||
await w.webContents.executeJavaScript('installBeforeUnload(2)', true);
|
||||
await w.webContents.executeJavaScript('preventNextBeforeUnload()', true);
|
||||
w.reload();
|
||||
// Chromium does not emit 'before-unload-fired' on WebContents for
|
||||
// navigations, so we have to use other ways to know if beforeunload
|
||||
// is fired.
|
||||
await emittedUntil(w.webContents, 'console-message', isBeforeUnload);
|
||||
{
|
||||
const [e] = await emittedOnce(ipcMain, 'onbeforeunload');
|
||||
e.returnValue = null;
|
||||
}
|
||||
|
||||
await w.webContents.executeJavaScript('preventNextBeforeUnload()', true);
|
||||
w.reload();
|
||||
await emittedUntil(w.webContents, 'console-message', isBeforeUnload);
|
||||
{
|
||||
const [e] = await emittedOnce(ipcMain, 'onbeforeunload');
|
||||
e.returnValue = null;
|
||||
}
|
||||
|
||||
w.webContents.removeListener('did-start-navigation', navigationListener);
|
||||
w.reload();
|
||||
@@ -2697,14 +2736,19 @@ describe('BrowserWindow module', () => {
|
||||
const navigationListener = () => { expect.fail('Reload was not prevented'); };
|
||||
w.webContents.once('did-start-navigation', navigationListener);
|
||||
|
||||
await w.webContents.executeJavaScript('installBeforeUnload(2)', true);
|
||||
await w.webContents.executeJavaScript('preventNextBeforeUnload()', true);
|
||||
w.loadURL('about:blank');
|
||||
// Chromium does not emit 'before-unload-fired' on WebContents for
|
||||
// navigations, so we have to use other ways to know if beforeunload
|
||||
// is fired.
|
||||
await emittedUntil(w.webContents, 'console-message', isBeforeUnload);
|
||||
{
|
||||
const [e] = await emittedOnce(ipcMain, 'onbeforeunload');
|
||||
e.returnValue = null;
|
||||
}
|
||||
|
||||
await w.webContents.executeJavaScript('preventNextBeforeUnload()', true);
|
||||
w.loadURL('about:blank');
|
||||
await emittedUntil(w.webContents, 'console-message', isBeforeUnload);
|
||||
{
|
||||
const [e] = await emittedOnce(ipcMain, 'onbeforeunload');
|
||||
e.returnValue = null;
|
||||
}
|
||||
|
||||
w.webContents.removeListener('did-start-navigation', navigationListener);
|
||||
w.loadURL('about:blank');
|
||||
@@ -4128,7 +4172,7 @@ describe('BrowserWindow module', () => {
|
||||
window.postMessage({openedLocation}, '*')
|
||||
`);
|
||||
const [, data] = await p;
|
||||
expect(data.pageContext.openedLocation).to.equal('about:blank');
|
||||
expect(data.pageContext.openedLocation).to.equal('');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -38,21 +38,4 @@ ifdescribe(process.platform !== 'win32')('globalShortcut module', () => {
|
||||
expect(globalShortcut.isRegistered(accelerators[0])).to.be.false('first unregistered');
|
||||
expect(globalShortcut.isRegistered(accelerators[1])).to.be.false('second unregistered');
|
||||
});
|
||||
|
||||
it('does not crash when registering media keys as global shortcuts', () => {
|
||||
const accelerators = [
|
||||
'VolumeUp',
|
||||
'VolumeDown',
|
||||
'VolumeMute',
|
||||
'MediaNextTrack',
|
||||
'MediaPreviousTrack',
|
||||
'MediaStop', 'MediaPlayPause'
|
||||
];
|
||||
|
||||
expect(() => {
|
||||
globalShortcut.registerAll(accelerators, () => {});
|
||||
}).to.not.throw();
|
||||
|
||||
globalShortcut.unregisterAll();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ import { closeWindow } from './window-helpers';
|
||||
const fixturesPath = path.resolve(__dirname, 'fixtures');
|
||||
|
||||
describe('Menu module', function () {
|
||||
this.timeout(5000);
|
||||
describe('Menu.buildFromTemplate', () => {
|
||||
it('should be able to attach extra fields', () => {
|
||||
const menu = Menu.buildFromTemplate([
|
||||
@@ -884,14 +885,9 @@ describe('Menu module', function () {
|
||||
const appProcess = cp.spawn(process.execPath, [appPath]);
|
||||
|
||||
let output = '';
|
||||
await new Promise((resolve) => {
|
||||
appProcess.stdout.on('data', data => {
|
||||
output += data;
|
||||
if (data.indexOf('Window has') > -1) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
appProcess.stdout.on('data', data => { output += data; });
|
||||
|
||||
await emittedOnce(appProcess, 'exit');
|
||||
expect(output).to.include('Window has no menu');
|
||||
});
|
||||
|
||||
|
||||
@@ -366,11 +366,11 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => {
|
||||
const w = makeWindow();
|
||||
const remotely = makeRemotely(w);
|
||||
|
||||
it('can serialize an empty nativeImage from renderer to main', async () => {
|
||||
const getImageEmpty = (img: NativeImage) => img.isEmpty();
|
||||
it('can serialize an empty nativeImage', async () => {
|
||||
const getEmptyImage = (img: NativeImage) => img.isEmpty();
|
||||
|
||||
w().webContents.once('remote-get-global', (event) => {
|
||||
event.returnValue = getImageEmpty;
|
||||
event.returnValue = getEmptyImage;
|
||||
});
|
||||
|
||||
await expect(remotely(() => {
|
||||
@@ -379,23 +379,11 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => {
|
||||
})).to.eventually.be.true();
|
||||
});
|
||||
|
||||
it('can serialize an empty nativeImage from main to renderer', async () => {
|
||||
w().webContents.once('remote-get-global', (event) => {
|
||||
const emptyImage = require('electron').nativeImage.createEmpty();
|
||||
event.returnValue = emptyImage;
|
||||
});
|
||||
|
||||
await expect(remotely(() => {
|
||||
const image = require('electron').remote.getGlobal('someFunction');
|
||||
return image.isEmpty();
|
||||
})).to.eventually.be.true();
|
||||
});
|
||||
|
||||
it('can serialize a non-empty nativeImage from renderer to main', async () => {
|
||||
const getImageSize = (img: NativeImage) => img.getSize();
|
||||
it('can serialize a non-empty nativeImage', async () => {
|
||||
const getNonEmptyImage = (img: NativeImage) => img.getSize();
|
||||
|
||||
w().webContents.once('remote-get-global', (event) => {
|
||||
event.returnValue = getImageSize;
|
||||
event.returnValue = getNonEmptyImage;
|
||||
});
|
||||
|
||||
await expect(remotely(() => {
|
||||
@@ -405,18 +393,6 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => {
|
||||
})).to.eventually.deep.equal({ width: 2, height: 2 });
|
||||
});
|
||||
|
||||
it('can serialize a non-empty nativeImage from main to renderer', async () => {
|
||||
w().webContents.once('remote-get-global', (event) => {
|
||||
const nonEmptyImage = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAFklEQVQYlWP8//8/AwMDEwMDAwMDAwAkBgMBBMzldwAAAABJRU5ErkJggg==');
|
||||
event.returnValue = nonEmptyImage;
|
||||
});
|
||||
|
||||
await expect(remotely(() => {
|
||||
const image = require('electron').remote.getGlobal('someFunction');
|
||||
return image.getSize();
|
||||
})).to.eventually.deep.equal({ width: 2, height: 2 });
|
||||
});
|
||||
|
||||
it('can properly create a menu with an nativeImage icon in the renderer', async () => {
|
||||
await expect(remotely(() => {
|
||||
const { remote, nativeImage } = require('electron');
|
||||
|
||||
@@ -42,22 +42,23 @@ describe('webContents module', () => {
|
||||
});
|
||||
|
||||
describe('will-prevent-unload event', function () {
|
||||
// TODO(nornagon): de-flake this properly
|
||||
this.retries(3);
|
||||
|
||||
afterEach(closeAllWindows);
|
||||
it('does not emit if beforeunload returns undefined', async () => {
|
||||
it('does not emit if beforeunload returns undefined', (done) => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.once('closed', () => done());
|
||||
w.webContents.once('will-prevent-unload', () => {
|
||||
expect.fail('should not have fired');
|
||||
});
|
||||
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-undefined.html'));
|
||||
const wait = emittedOnce(w, 'closed');
|
||||
w.close();
|
||||
await wait;
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-undefined.html'));
|
||||
});
|
||||
|
||||
it('emits if beforeunload returns false', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-false.html'));
|
||||
w.close();
|
||||
w.webContents.executeJavaScript('run()', true);
|
||||
await emittedOnce(w.webContents, 'will-prevent-unload');
|
||||
});
|
||||
|
||||
@@ -65,9 +66,8 @@ describe('webContents module', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.webContents.once('will-prevent-unload', event => event.preventDefault());
|
||||
await w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-false.html'));
|
||||
const wait = emittedOnce(w, 'closed');
|
||||
w.close();
|
||||
await wait;
|
||||
w.webContents.executeJavaScript('run()', true);
|
||||
await emittedOnce(w, 'closed');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1233,10 +1233,7 @@ describe('chromium features', () => {
|
||||
w.loadURL(pdfSource);
|
||||
const [, contents] = await emittedOnce(app, 'web-contents-created');
|
||||
expect(contents.getURL()).to.equal('chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/index.html');
|
||||
await new Promise((resolve) => {
|
||||
contents.on('did-finish-load', resolve);
|
||||
contents.on('did-frame-finish-load', resolve);
|
||||
});
|
||||
await emittedOnce(contents, 'did-finish-load');
|
||||
});
|
||||
|
||||
it('opens when loading a pdf resource in a iframe', async () => {
|
||||
@@ -1244,10 +1241,7 @@ describe('chromium features', () => {
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'pages', 'pdf-in-iframe.html'));
|
||||
const [, contents] = await emittedOnce(app, 'web-contents-created');
|
||||
expect(contents.getURL()).to.equal('chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/index.html');
|
||||
await new Promise((resolve) => {
|
||||
contents.on('did-finish-load', resolve);
|
||||
contents.on('did-frame-finish-load', resolve);
|
||||
});
|
||||
await emittedOnce(contents, 'did-finish-load');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -294,12 +294,11 @@ describe('chrome extensions', () => {
|
||||
it('loads a devtools extension', async () => {
|
||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||
customSession.loadExtension(path.join(fixtures, 'extensions', 'devtools-extension'));
|
||||
const winningMessage = emittedOnce(ipcMain, 'winning');
|
||||
const w = new BrowserWindow({ show: true, webPreferences: { session: customSession, nodeIntegration: true } });
|
||||
await w.loadURL(url);
|
||||
w.webContents.openDevTools();
|
||||
showLastDevToolsPanel(w);
|
||||
await winningMessage;
|
||||
await emittedOnce(ipcMain, 'winning');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
<html>
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
function installBeforeUnload(removeAfterNTimes) {
|
||||
let count = 0
|
||||
function preventNextBeforeUnload() {
|
||||
window.addEventListener('beforeunload', function handler(e) {
|
||||
setTimeout(() => console.log('beforeunload'))
|
||||
if (++count <= removeAfterNTimes) {
|
||||
e.preventDefault();
|
||||
e.returnValue = '';
|
||||
}
|
||||
e.preventDefault();
|
||||
e.returnValue = '';
|
||||
window.removeEventListener('beforeunload', handler)
|
||||
setTimeout(function() {
|
||||
require('electron').ipcRenderer.sendSync('onbeforeunload')
|
||||
}, 0);
|
||||
return false;
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -4,11 +4,16 @@
|
||||
// Only prevent unload on the first window close
|
||||
var unloadPrevented = false;
|
||||
window.onbeforeunload = function() {
|
||||
setTimeout(function() {
|
||||
require('electron').ipcRenderer.sendSync('onbeforeunload');
|
||||
}, 0);
|
||||
|
||||
if (!unloadPrevented) {
|
||||
unloadPrevented = true;
|
||||
return '';
|
||||
}
|
||||
}
|
||||
window.onload = () => window.close();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
<html>
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
// Only prevent unload on the first window close
|
||||
var unloadPrevented = false;
|
||||
window.onbeforeunload = function() {
|
||||
if (!unloadPrevented) {
|
||||
unloadPrevented = true;
|
||||
console.log('prevent')
|
||||
return false;
|
||||
function run() {
|
||||
// Only prevent unload on the first window close
|
||||
var unloadPrevented = false;
|
||||
window.onbeforeunload = function() {
|
||||
setTimeout(function() {
|
||||
require('electron').ipcRenderer.sendSync('onbeforeunload');
|
||||
}, 0);
|
||||
if (!unloadPrevented) {
|
||||
unloadPrevented = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// unload events don't get run unless load events have run.
|
||||
if (document.readyState === 'complete')
|
||||
window.close()
|
||||
else
|
||||
window.onload = () => window.close()
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
window.onbeforeunload = function() {
|
||||
setTimeout(function() {
|
||||
require('electron').ipcRenderer.sendSync('onbeforeunload');
|
||||
}, 0);
|
||||
}
|
||||
window.onload = () => window.close();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -37,7 +37,7 @@ protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: 'bar', privileges: { standard: true } }
|
||||
]);
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
app.whenReady().then(() => {
|
||||
require('ts-node/register');
|
||||
|
||||
const argv = require('yargs')
|
||||
@@ -68,45 +68,53 @@ app.whenReady().then(async () => {
|
||||
if (argv.grep) mocha.grep(argv.grep);
|
||||
if (argv.invert) mocha.invert();
|
||||
|
||||
const filter = (file) => {
|
||||
if (!/-spec\.[tj]s$/.test(file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This allows you to run specific modules only:
|
||||
// npm run test -match=menu
|
||||
const moduleMatch = process.env.npm_config_match
|
||||
? new RegExp(process.env.npm_config_match, 'g')
|
||||
: null;
|
||||
if (moduleMatch && !moduleMatch.test(file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const baseElectronDir = path.resolve(__dirname, '..');
|
||||
if (argv.files && !argv.files.includes(path.relative(baseElectronDir, file))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const getFiles = require('../spec/static/get-files');
|
||||
const testFiles = await getFiles(__dirname, { filter });
|
||||
testFiles.sort().forEach((file) => {
|
||||
mocha.addFile(file);
|
||||
// Read all test files.
|
||||
const walker = require('walkdir').walk(__dirname, {
|
||||
no_recurse: true
|
||||
});
|
||||
|
||||
const cb = () => {
|
||||
// Ensure the callback is called after runner is defined
|
||||
process.nextTick(() => {
|
||||
process.exit(runner.failures);
|
||||
// This allows you to run specific modules only:
|
||||
// npm run test -match=menu
|
||||
const moduleMatch = process.env.npm_config_match
|
||||
? new RegExp(process.env.npm_config_match, 'g')
|
||||
: null;
|
||||
|
||||
const testFiles = [];
|
||||
walker.on('file', (file) => {
|
||||
if (/-spec\.[tj]s$/.test(file) &&
|
||||
(!moduleMatch || moduleMatch.test(file))) {
|
||||
testFiles.push(file);
|
||||
}
|
||||
});
|
||||
|
||||
const baseElectronDir = path.resolve(__dirname, '..');
|
||||
|
||||
walker.on('end', () => {
|
||||
testFiles.sort();
|
||||
testFiles.forEach((file) => {
|
||||
if (!argv.files || argv.files.includes(path.relative(baseElectronDir, file))) {
|
||||
mocha.addFile(file);
|
||||
}
|
||||
});
|
||||
};
|
||||
const cb = () => {
|
||||
// Ensure the callback is called after runner is defined
|
||||
process.nextTick(() => {
|
||||
process.exit(runner.failures);
|
||||
});
|
||||
};
|
||||
|
||||
// Set up chai in the correct order
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-as-promised'));
|
||||
chai.use(require('dirty-chai'));
|
||||
// Set up chai in the correct order
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-as-promised'));
|
||||
chai.use(require('dirty-chai'));
|
||||
|
||||
const runner = mocha.run(cb);
|
||||
const runner = mocha.run(cb);
|
||||
});
|
||||
});
|
||||
|
||||
function partition (xs, f) {
|
||||
const trues = [];
|
||||
const falses = [];
|
||||
xs.forEach(x => (f(x) ? trues : falses).push(x));
|
||||
return [trues, falses];
|
||||
}
|
||||
|
||||
3
spec/fixtures/api/beforeunload-false.html
vendored
3
spec/fixtures/api/beforeunload-false.html
vendored
@@ -4,6 +4,9 @@
|
||||
// Only prevent unload on the first window close
|
||||
var unloadPrevented = false;
|
||||
window.onbeforeunload = function() {
|
||||
setTimeout(function() {
|
||||
require('electron').ipcRenderer.sendSync('onbeforeunload');
|
||||
}, 0);
|
||||
if (!unloadPrevented) {
|
||||
unloadPrevented = true;
|
||||
return false;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
async function getFiles (directoryPath, { filter = null } = {}) {
|
||||
const files = [];
|
||||
const walker = require('walkdir').walk(directoryPath, {
|
||||
no_recurse: true
|
||||
});
|
||||
walker.on('file', (file) => {
|
||||
if (!filter || filter(file)) {
|
||||
files.push(file);
|
||||
}
|
||||
});
|
||||
await new Promise((resolve) => walker.on('end', resolve));
|
||||
return files;
|
||||
}
|
||||
|
||||
module.exports = getFiles;
|
||||
@@ -1,7 +1,7 @@
|
||||
<body>
|
||||
<script src="jquery-2.0.3.min.js"></script>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
(async function() {
|
||||
(function() {
|
||||
// Deprecated APIs are still supported and should be tested.
|
||||
process.throwDeprecation = false
|
||||
|
||||
@@ -49,45 +49,47 @@
|
||||
if (query.grep) mocha.grep(query.grep)
|
||||
if (query.invert) mocha.invert()
|
||||
|
||||
const filter = (file) => {
|
||||
if (!/-spec\.js$/.test(file)) {
|
||||
return false
|
||||
}
|
||||
const files = query.files ? query.files.split(',') : undefined
|
||||
|
||||
// This allows you to run specific modules only:
|
||||
// npm run test -match=menu
|
||||
const moduleMatch = process.env.npm_config_match
|
||||
? new RegExp(process.env.npm_config_match, 'g')
|
||||
: null
|
||||
if (moduleMatch && !moduleMatch.test(file)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const files = query.files ? query.files.split(',') : undefined
|
||||
const baseElectronDir = path.resolve(__dirname, '..', '..')
|
||||
if (files && !files.includes(path.relative(baseElectronDir, file))) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const getFiles = require('./get-files')
|
||||
const testFiles = await getFiles(path.dirname(__dirname), { filter })
|
||||
testFiles.sort().forEach((file) => {
|
||||
mocha.addFile(file)
|
||||
// Read all test files.
|
||||
const walker = require('walkdir').walk(path.dirname(__dirname), {
|
||||
no_recurse: true
|
||||
})
|
||||
|
||||
// Set up chai in the correct order
|
||||
const chai = require('chai')
|
||||
chai.use(require('chai-as-promised'))
|
||||
chai.use(require('dirty-chai'))
|
||||
// This allows you to run specific modules only:
|
||||
// npm run test -match=menu
|
||||
const moduleMatch = process.env.npm_config_match
|
||||
? new RegExp(process.env.npm_config_match, 'g')
|
||||
: null
|
||||
|
||||
const runner = mocha.run(() => {
|
||||
// Ensure the callback is called after runner is defined
|
||||
setTimeout(() => {
|
||||
ipcRenderer.send('process.exit', runner.failures)
|
||||
}, 0)
|
||||
const testFiles = []
|
||||
walker.on('file', (file) => {
|
||||
if (/-spec\.js$/.test(file) && (!moduleMatch || moduleMatch.test(file))) {
|
||||
testFiles.push(file)
|
||||
}
|
||||
})
|
||||
|
||||
const baseElectronDir = path.resolve(__dirname, '..', '..')
|
||||
|
||||
walker.on('end', () => {
|
||||
testFiles.sort()
|
||||
testFiles.forEach((file) => {
|
||||
if (!files || files.includes(path.relative(baseElectronDir, file))) {
|
||||
mocha.addFile(file)
|
||||
}
|
||||
})
|
||||
|
||||
// Set up chai in the correct order
|
||||
const chai = require('chai')
|
||||
chai.use(require('chai-as-promised'))
|
||||
chai.use(require('dirty-chai'))
|
||||
|
||||
const runner = mocha.run(() => {
|
||||
// Ensure the callback is called after runner is defined
|
||||
setTimeout(() => {
|
||||
ipcRenderer.send('process.exit', runner.failures)
|
||||
}, 0)
|
||||
})
|
||||
})
|
||||
})()
|
||||
</script>
|
||||
|
||||
2
typings/internal-electron.d.ts
vendored
2
typings/internal-electron.d.ts
vendored
@@ -87,6 +87,8 @@ declare namespace Electron {
|
||||
namespace Main {
|
||||
const deprecate: ElectronInternal.DeprecationUtil;
|
||||
}
|
||||
|
||||
class View {}
|
||||
}
|
||||
|
||||
declare namespace ElectronInternal {
|
||||
|
||||
Reference in New Issue
Block a user