diff --git a/app/actions.js b/app/actions.js
index bbe327a..967ea86 100644
--- a/app/actions.js
+++ b/app/actions.js
@@ -1,7 +1,5 @@
const { app } = require('electron')
-const { createWindow } = require('./windows')
-
const { accelerators } = require('./config')
const FOCUS_URL_BAR_SCRIPT = `
@@ -12,118 +10,123 @@ const OPEN_FIND_BAR_SCRIPT = `
document.getElementById('find').show()
`
-module.exports = {
- OpenDevTools: {
- label: 'Open Dev Tools',
- accelerator: accelerators.OpenDevTools,
- click: onOpenDevTools
- },
- NewWindow: {
- label: 'New Window',
- click: onNewWindow,
- accelerator: accelerators.NewWindow
- },
- Forward: {
- label: 'Forward',
- accelerator: accelerators.Forward,
- click: onGoForward
- },
- Back: {
- label: 'Back',
- accelerator: accelerators.Back,
- click: onGoBack
- },
- FocusURLBar: {
- label: 'Focus URL Bar',
- click: onFocusURlBar,
- accelerator: accelerators.FocusURLBar
- },
- FindInPage: {
- label: 'Find in Page',
- click: onFindInPage,
- accelerator: accelerators.FindInPage
- },
- Reload: {
- label: 'Reload',
- accelerator: accelerators.Reload,
- click: onReload
- },
- HardReload: {
- label: 'Hard Reload',
- accelerator: accelerators.HardReload,
- click: onHardReload
- },
- LearnMore: {
- label: 'Learn More',
- accelerator: accelerators.LearnMore,
- click: onLearMore
- },
- SetAsDefault: {
- label: 'Set as default browser',
- accelerator: accelerators.SetAsDefault,
- click: onSetAsDefault
+module.exports = { createActions }
+
+function createActions ({
+ createWindow
+}) {
+ return {
+ OpenDevTools: {
+ label: 'Open Dev Tools',
+ accelerator: accelerators.OpenDevTools,
+ click: onOpenDevTools
+ },
+ NewWindow: {
+ label: 'New Window',
+ click: onNewWindow,
+ accelerator: accelerators.NewWindow
+ },
+ Forward: {
+ label: 'Forward',
+ accelerator: accelerators.Forward,
+ click: onGoForward
+ },
+ Back: {
+ label: 'Back',
+ accelerator: accelerators.Back,
+ click: onGoBack
+ },
+ FocusURLBar: {
+ label: 'Focus URL Bar',
+ click: onFocusURlBar,
+ accelerator: accelerators.FocusURLBar
+ },
+ FindInPage: {
+ label: 'Find in Page',
+ click: onFindInPage,
+ accelerator: accelerators.FindInPage
+ },
+ Reload: {
+ label: 'Reload',
+ accelerator: accelerators.Reload,
+ click: onReload
+ },
+ HardReload: {
+ label: 'Hard Reload',
+ accelerator: accelerators.HardReload,
+ click: onHardReload
+ },
+ LearnMore: {
+ label: 'Learn More',
+ accelerator: accelerators.LearnMore,
+ click: onLearMore
+ },
+ SetAsDefault: {
+ label: 'Set as default browser',
+ accelerator: accelerators.SetAsDefault,
+ click: onSetAsDefault
+ }
+ }
+ async function onSetAsDefault () {
+ app.setAsDefaultProtocolClient('http')
+ app.setAsDefaultProtocolClient('https')
}
-}
-
-async function onSetAsDefault () {
- app.setAsDefaultProtocolClient('http')
- app.setAsDefaultProtocolClient('https')
-}
-async function onLearMore () {
- const { shell } = require('electron')
- await shell.openExternal('https://github.com/RangerMauve/agregore-browser')
-}
+ async function onLearMore () {
+ const { shell } = require('electron')
+ await shell.openExternal('https://github.com/RangerMauve/agregore-browser')
+ }
-function onOpenDevTools (event, focusedWindow, focusedWebContents) {
- const contents = getContents(focusedWindow)
- for (const webContents of contents) {
- webContents.openDevTools()
+ function onOpenDevTools (event, focusedWindow, focusedWebContents) {
+ const contents = getContents(focusedWindow)
+ for (const webContents of contents) {
+ webContents.openDevTools()
+ }
}
-}
-function onNewWindow (event, focusedWindow, focusedWebContents) {
- createWindow()
-}
+ function onNewWindow (event, focusedWindow, focusedWebContents) {
+ createWindow()
+ }
-function onFocusURlBar (event, focusedWindow) {
- focusedWindow.webContents.focus()
- focusedWindow.webContents.executeJavaScript(FOCUS_URL_BAR_SCRIPT, true)
-}
+ function onFocusURlBar (event, focusedWindow) {
+ focusedWindow.webContents.focus()
+ focusedWindow.webContents.executeJavaScript(FOCUS_URL_BAR_SCRIPT, true)
+ }
-function onFindInPage (event, focusedWindow) {
- focusedWindow.webContents.focus()
- focusedWindow.webContents.executeJavaScript(OPEN_FIND_BAR_SCRIPT, true)
-}
+ function onFindInPage (event, focusedWindow) {
+ focusedWindow.webContents.focus()
+ focusedWindow.webContents.executeJavaScript(OPEN_FIND_BAR_SCRIPT, true)
+ }
-function onReload (event, focusedWindow, focusedWebContents) {
+ function onReload (event, focusedWindow, focusedWebContents) {
// Reload
- for (const webContents of getContents(focusedWindow)) {
- webContents.reload()
+ for (const webContents of getContents(focusedWindow)) {
+ webContents.reload()
+ }
}
-}
-function onHardReload (event, focusedWindow, focusedWebContents) {
+ function onHardReload (event, focusedWindow, focusedWebContents) {
// Hard reload
- for (const webContents of getContents(focusedWindow)) {
- webContents.reloadIgnoringCache()
+ for (const webContents of getContents(focusedWindow)) {
+ webContents.reloadIgnoringCache()
+ }
}
-}
-function onGoForward (event, focusedWindow) {
- for (const webContents of getContents(focusedWindow)) {
- webContents.goForward()
+ function onGoForward (event, focusedWindow) {
+ for (const webContents of getContents(focusedWindow)) {
+ webContents.goForward()
+ }
}
-}
-function onGoBack (event, focusedWindow) {
- for (const webContents of getContents(focusedWindow)) {
- webContents.goBack()
+ function onGoBack (event, focusedWindow) {
+ for (const webContents of getContents(focusedWindow)) {
+ webContents.goBack()
+ }
}
-}
-function getContents (focusedWindow) {
- const views = focusedWindow.getBrowserViews()
- if (!views.length) return [focusedWindow.webContents]
- return views.map(({ webContents }) => webContents)
+ function getContents (focusedWindow) {
+ const views = focusedWindow.getBrowserViews()
+ if (!views.length) return [focusedWindow.webContents]
+ return views.map(({ webContents }) => webContents)
+ }
}
diff --git a/app/context-menus.js b/app/context-menus.js
new file mode 100644
index 0000000..4df3b59
--- /dev/null
+++ b/app/context-menus.js
@@ -0,0 +1,207 @@
+const {
+ Menu,
+ MenuItem,
+ dialog,
+ app,
+ clipboard
+} = require('electron')
+
+const path = require('path').posix
+
+module.exports = {
+ attachContextMenus
+}
+
+function attachContextMenus ({ window, createWindow }) {
+ window.webContents.on('context-menu', headerContextMenu)
+ window.web.on('context-menu', pageContextMenu)
+
+ function headerContextMenu (event, params) {
+ if (params.inputFieldType === 'plainText') {
+ showContextMenu([
+ historyBufferGroup(params, false),
+ editGroup(params, true)
+ ])
+ }
+ }
+
+ function pageContextMenu (event, params) {
+ showContextMenu([
+ navigationGroup(window.web, params),
+ historyBufferGroup(params),
+ linkGroup(params),
+ saveGroup(params),
+ editGroup(params),
+ developmentGroup(window.web, params)
+ ])
+ }
+
+ function showContextMenu (groups) {
+ const menu = new Menu()
+ groups
+ .filter(group => group != null)
+ .flatMap((group, index, array) => {
+ if (index + 1 < array.length) {
+ const seperator = new MenuItem({ type: 'separator' })
+ group.push(seperator)
+ }
+ return group
+ })
+ .forEach(item => menu.append(item))
+ menu.popup(window.window)
+ }
+
+ function historyBufferGroup ({ editFlags, isEditable }, showRedo = true) {
+ return !isEditable ? null : [
+ new MenuItem({
+ label: 'Undo',
+ enabled: editFlags.canUndo,
+ accelerator: 'CommandOrControl+Z',
+ role: 'undo'
+ }),
+ new MenuItem({
+ label: 'Redo',
+ enabled: editFlags.canRedo,
+ visible: showRedo,
+ accelerator: 'CommandOrControl+Y',
+ role: 'redo'
+ })
+ ]
+ }
+
+ function editGroup ({ editFlags, isEditable, selectionText }) {
+ return !isEditable && !selectionText ? null : [
+ new MenuItem({
+ label: 'Cut',
+ enabled: editFlags.canCut,
+ accelerator: 'CommandOrControl+X',
+ role: 'cut'
+ }),
+ new MenuItem({
+ label: 'Copy',
+ enabled: editFlags.canCopy,
+ accelerator: 'CommandOrControl+C',
+ role: 'copy'
+ }),
+ new MenuItem({
+ label: 'Paste',
+ enabled: editFlags.canPaste,
+ accelerator: 'CommandOrControl+P',
+ role: 'paste'
+ }),
+ new MenuItem({
+ label: 'Delete',
+ enabled: editFlags.canDelete,
+ role: 'delete'
+ }),
+ new MenuItem({
+ type: 'separator'
+ }),
+ new MenuItem({
+ label: 'Select All',
+ enabled: editFlags.canSelectAll,
+ accelerator: 'CommandOrControl+A',
+ role: 'selectAll'
+ })
+ ]
+ }
+
+ function navigationGroup (wc, { mediaType, isEditable }) {
+ return mediaType !== 'none' || isEditable ? null : [
+ new MenuItem({
+ label: 'Back',
+ enabled: wc.canGoBack(),
+ click: wc.goBack
+ }),
+ new MenuItem({
+ label: 'Forward',
+ enabled: wc.canGoForward(),
+ click: wc.goForward
+ }),
+ new MenuItem({
+ label: 'Reload',
+ click: wc.reload
+ }),
+ new MenuItem({
+ label: 'Hard Reload',
+ click: wc.reloadIgnoringCache
+ })
+ ]
+ }
+
+ function developmentGroup (wc, { x, y }) {
+ return [
+ new MenuItem({
+ label: 'Inspect',
+ click () {
+ wc.inspectElement(x, y)
+ if (wc.isDevToolsOpened()) wc.devToolsWebContents.focus()
+ }
+ })
+ ]
+ }
+
+ function linkGroup ({ linkURL }) {
+ return !linkURL.length ? null : [
+ new MenuItem({
+ label: 'Open link in new window',
+ click: () => createWindow(linkURL)
+ }),
+ new MenuItem({
+ label: 'Copy link address',
+ click: () => clipboard.writeText(linkURL)
+ })
+ ]
+ }
+
+ function saveGroup ({ srcURL }) {
+ return !srcURL.length ? null : [
+ new MenuItem({
+ label: 'Save As',
+ click: (_, browserWindow) => saveAs(srcURL, browserWindow)
+ })
+ ]
+ }
+
+ async function saveAs (link, browserWindow) {
+ const downloads = app.getPath('downloads')
+ const name = path.basename(link)
+ const defaultPath = path.join(downloads, name)
+ const { filePath } = await dialog.showSaveDialog(browserWindow, {
+ defaultPath
+ })
+
+ if (!filePath) return
+
+ await window.webContents.executeJavaScript(`
+ (async () => {
+ const fs = require('fs')
+ const pump = require('pump')
+ const { Readable } = require('stream')
+ const link = ${JSON.stringify(link)}
+ const filePath = ${JSON.stringify(filePath)}
+
+ const response = await window.fetch(link)
+
+ pump(
+ Readable.from(consumeBody(response.body)),
+ fs.createWriteStream(filePath)
+ )
+
+ async function * consumeBody (body) {
+ const reader = body.getReader()
+
+ try {
+ const { done, value } = await reader.read()
+
+ if (done) return
+
+ yield value
+ } finally {
+ reader.releaseLock()
+ }
+ }
+ })()
+ `)
+ }
+}
diff --git a/app/extensions/index.js b/app/extensions/index.js
index e2f1af6..71c1d87 100644
--- a/app/extensions/index.js
+++ b/app/extensions/index.js
@@ -1,11 +1,13 @@
const path = require('path')
const fs = require('fs-extra')
-const { ExtensibleSession } = require('electron-extensions/main')
-const { createWindow } = require('../windows')
+const { ExtensibleSession } = require('../../node_modules/electron-extensions/main')
const { webContents } = require('electron')
+const DEFAULT_PARTITION = 'persist:web-content'
+
let extensions = null
+let createWindow = null
module.exports = {
init,
@@ -43,9 +45,11 @@ function getExtension (name) {
return extensions.extensions[name]
}
-async function init () {
+async function init ({ partition = DEFAULT_PARTITION, createWindow: _createWindow } = {}) {
+ createWindow = _createWindow
+
extensions = new ExtensibleSession({
- partition: 'persist:web-content',
+ partition,
blacklist: ['agregore-browser://*/*', 'file://*/*']
})
diff --git a/app/main.js b/app/main.js
index 3a9de18..de26322 100644
--- a/app/main.js
+++ b/app/main.js
@@ -1,8 +1,10 @@
const { app, BrowserWindow, session } = require('electron')
const protocols = require('./protocols')
+const { createActions } = require('./actions')
const { registerMenu } = require('./menu')
-const { createWindow, saveOpen, loadFromHistory } = require('./windows')
+const { attachContextMenus } = require('./context-menus')
+const { WindowManager } = require('./window')
const Extensions = require('./extensions')
const history = require('./history')
@@ -15,12 +17,22 @@ if (!gotTheLock) {
} else {
app.on('second-instance', (event, argv) => {
const urls = argv.filter((arg) => arg.includes('://'))
- urls.map((url) => createWindow(url))
+ urls.map((url) => windowManager.open({ url }))
})
}
+const windowManager = new WindowManager({
+ onSearch: (...args) => history.search(...args)
+})
+
protocols.registerPriviledges()
+const actions = createActions({
+ createWindow
+})
+
+windowManager.on('open', (window) => attachContextMenus({ window, createWindow }))
+
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
@@ -39,34 +51,38 @@ app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) {
- createWindow()
+ windowManager.open()
}
})
app.on('before-quit', () => {
- saveOpen()
+ windowManager.saveOpened()
})
async function onready () {
const webSession = session.fromPartition(WEB_PARTITION)
await protocols.setupProtocols(webSession)
- await registerMenu()
+ await registerMenu(actions)
- await Extensions.init(webSession)
+ await Extensions.init({ partition: WEB_PARTITION, createWindow })
const historyExtension = await Extensions.getExtension('agregore-history')
history.setExtension(historyExtension)
const rootURL = new URL(process.cwd(), 'file://')
+ const opened = await windowManager.openSaved()
+
const urls = process.argv
.slice(2)
.filter((arg) => arg.includes('/'))
.map((arg) => arg.includes('://') ? arg : (new URL(arg, rootURL)).href)
- if (urls.length) urls.map(createWindow)
- else {
- const opened = await loadFromHistory()
- if (!opened.length) createWindow()
- }
+ if (urls.length) {
+ urls.map((url) => {
+ windowManager.open({ url })
+ })
+ } else if (!opened.length) windowManager.open()
}
+
+function createWindow (url, options = {}) { windowManager.open({ url, ...options }) }
diff --git a/app/menu.js b/app/menu.js
index 3ee2652..6127e45 100644
--- a/app/menu.js
+++ b/app/menu.js
@@ -2,24 +2,24 @@ const { Menu, app } = require('electron')
const isMac = process.platform === 'darwin'
-const {
- OpenDevTools,
- NewWindow,
- Forward,
- Back,
- FocusURLBar,
- FindInPage,
- Reload,
- HardReload,
- LearnMore,
- SetAsDefault
-} = require('./actions')
-
module.exports = {
registerMenu
}
-function registerMenu () {
+function registerMenu (actions) {
+ const {
+ OpenDevTools,
+ NewWindow,
+ Forward,
+ Back,
+ FocusURLBar,
+ FindInPage,
+ Reload,
+ HardReload,
+ LearnMore,
+ SetAsDefault
+ } = actions
+
const template = [
// { role: 'appMenu' }
...(isMac ? [{
diff --git a/app/protocols/index.js b/app/protocols/index.js
index 2ade4ab..21eee56 100644
--- a/app/protocols/index.js
+++ b/app/protocols/index.js
@@ -6,7 +6,8 @@ const P2P_PRIVILEDGES = {
allowServiceWorkers: true,
supportFetchAPI: true,
bypassCSP: false,
- corsEnabled: true
+ corsEnabled: true,
+ stream: true
}
const BROWSER_PRIVILEDGES = {
diff --git a/app/ui/browser-actions.js b/app/ui/browser-actions.js
index 9b10af1..8bd6920 100644
--- a/app/ui/browser-actions.js
+++ b/app/ui/browser-actions.js
@@ -2,7 +2,8 @@
class BrowserActions extends HTMLElement {
async connectedCallback () {
- const { remote } = require('electron')
+ /*
+ const remote = require('@electron/remote')
const Extensions = remote.require('./extensions')
const actions = await Extensions.listActions()
@@ -18,7 +19,7 @@ class BrowserActions extends HTMLElement {
`
this.appendChild(button)
- }
+ } */
}
get tabId () {
diff --git a/app/ui/context-menus.js b/app/ui/context-menus.js
deleted file mode 100644
index 628433f..0000000
--- a/app/ui/context-menus.js
+++ /dev/null
@@ -1,190 +0,0 @@
-const electron = require('electron')
-const { remote, clipboard } = electron
-const { Menu, MenuItem } = remote || electron
-
-exports.headerContextMenu = function (event, params) {
- if (params.inputFieldType === 'plainText') {
- showContextMenu(this, [
- historyBufferGroup(params, false),
- editGroup(params, true)
- ])
- }
-}
-
-exports.pageContextMenu = function (event, params) {
- showContextMenu(this, [
- navigationGroup(this.webContents, params),
- historyBufferGroup(params),
- linkGroup(params),
- saveGroup(params),
- editGroup(params),
- developmentGroup(this.webContents, params)
- ])
-}
-
-function showContextMenu (browserWindow, groups) {
- const menu = new Menu()
- groups
- .filter(group => group != null)
- .flatMap((group, index, array) => {
- if (index + 1 < array.length) {
- const seperator = new MenuItem({ type: 'separator' })
- group.push(seperator)
- }
- return group
- })
- .forEach(item => menu.append(item))
- menu.popup(browserWindow)
-}
-
-function historyBufferGroup ({ editFlags, isEditable }, showRedo = true) {
- return !isEditable ? null : [
- new MenuItem({
- label: 'Undo',
- enabled: editFlags.canUndo,
- accelerator: 'CommandOrControl+Z',
- role: 'undo'
- }),
- new MenuItem({
- label: 'Redo',
- enabled: editFlags.canRedo,
- visible: showRedo,
- accelerator: 'CommandOrControl+Y',
- role: 'redo'
- })
- ]
-}
-
-function editGroup ({ editFlags, isEditable, selectionText }) {
- return !isEditable && !selectionText ? null : [
- new MenuItem({
- label: 'Cut',
- enabled: editFlags.canCut,
- accelerator: 'CommandOrControl+X',
- role: 'cut'
- }),
- new MenuItem({
- label: 'Copy',
- enabled: editFlags.canCopy,
- accelerator: 'CommandOrControl+C',
- role: 'copy'
- }),
- new MenuItem({
- label: 'Paste',
- enabled: editFlags.canPaste,
- accelerator: 'CommandOrControl+P',
- role: 'paste'
- }),
- new MenuItem({
- label: 'Delete',
- enabled: editFlags.canDelete,
- role: 'delete'
- }),
- new MenuItem({
- type: 'separator'
- }),
- new MenuItem({
- label: 'Select All',
- enabled: editFlags.canSelectAll,
- accelerator: 'CommandOrControl+A',
- role: 'selectAll'
- })
- ]
-}
-
-function navigationGroup (wc, { mediaType, isEditable }) {
- return mediaType !== 'none' || isEditable ? null : [
- new MenuItem({
- label: 'Back',
- enabled: wc.canGoBack(),
- click: wc.goBack
- }),
- new MenuItem({
- label: 'Forward',
- enabled: wc.canGoForward(),
- click: wc.goForward
- }),
- new MenuItem({
- label: 'Reload',
- click: wc.reload
- }),
- new MenuItem({
- label: 'Hard Reload',
- click: wc.reloadIgnoringCache
- })
- ]
-}
-
-function developmentGroup (wc, { x, y }) {
- return [
- new MenuItem({
- label: 'Inspect',
- click () {
- wc.inspectElement(x, y)
- if (wc.isDevToolsOpened()) wc.devToolsWebContents.focus()
- }
- })
- ]
-}
-
-function linkGroup ({ linkURL }) {
- return !linkURL.length ? null : [
- new MenuItem({
- label: 'Open link in new window',
- click: () => remote.require('./windows').createWindow(linkURL)
- }),
- new MenuItem({
- label: 'Copy link address',
- click: () => clipboard.writeText(linkURL)
- })
- ]
-}
-
-function saveGroup ({ srcURL }) {
- return !srcURL.length ? null : [
- new MenuItem({
- label: 'Save As',
- click: (_, browserWindow) => saveAs(srcURL, browserWindow)
- })
- ]
-}
-
-async function saveAs (link, browserWindow) {
- const fs = remote.require('fs')
- const path = remote.require('path').posix
- const pump = require('pump')
- const { dialog, app } = remote
- const { Readable } = require('stream')
- const downloads = app.getPath('downloads')
-
- const name = path.basename(link)
-
- const defaultPath = path.join(downloads, name)
-
- const response = await window.fetch(link)
-
- const { filePath } = await dialog.showSaveDialog(browserWindow, {
- defaultPath
- })
-
- if (!filePath) return
-
- pump(
- Readable.from(consumeBody(response.body)),
- fs.createWriteStream(filePath)
- )
-}
-
-async function * consumeBody (body) {
- const reader = body.getReader()
-
- try {
- const { done, value } = await reader.read()
-
- if (done) return
-
- yield value
- } finally {
- reader.releaseLock()
- }
-}
diff --git a/app/ui/current-window.js b/app/ui/current-window.js
new file mode 100644
index 0000000..ac037be
--- /dev/null
+++ b/app/ui/current-window.js
@@ -0,0 +1,67 @@
+window.getCurrentWindow = function getCurrentWindow () {
+ const { ipcRenderer } = require('electron')
+ const EventEmitter = require('events')
+
+ const EVENTS = [
+ 'navigating',
+ 'history-buttons-change',
+ 'page-title-updated',
+ 'close'
+ ]
+
+ class CurrentWindow extends EventEmitter {
+ constructor () {
+ super()
+
+ for (const name of EVENTS) {
+ ipcRenderer.on(`agregore-window-${name}`, (event, ...args) => this.emit(name, ...args))
+ }
+ }
+
+ async goBack () {
+ return this.invoke('goBack')
+ }
+
+ async goForward () {
+ return this.invoke('goForward')
+ }
+
+ async reload () {
+ return this.invoke('reload')
+ }
+
+ async focus () {
+ return this.invoke('focus')
+ }
+
+ async loadURL (url) {
+ return this.invoke('loadURL', url)
+ }
+
+ async getURL () {
+ return this.invoke('getURL')
+ }
+
+ async findInPage (value, opts) {
+ return this.invoke('findInPage', value, opts)
+ }
+
+ async stopFindInPage () {
+ return this.invoke('stopFindInPage')
+ }
+
+ async setBounds (rect) {
+ return this.invoke('setBounds', rect)
+ }
+
+ async searchHistory (query, limit = 8) {
+ return this.invoke('searchHistory', query, limit)
+ }
+
+ async invoke (name, ...args) {
+ return ipcRenderer.invoke(`agregore-window-${name}`, ...args)
+ }
+ }
+
+ return new CurrentWindow()
+}
diff --git a/app/ui/electron-browser-view.js b/app/ui/electron-browser-view.js
deleted file mode 100644
index ff4a6ac..0000000
--- a/app/ui/electron-browser-view.js
+++ /dev/null
@@ -1,266 +0,0 @@
-/* global HTMLElement, ResizeObserver, CustomEvent, customElements */
-
-class BrowserViewElement extends HTMLElement {
- static EVENTS () {
- return [
- 'did-finish-load',
- 'did-fail-load',
- 'did-fail-provisional-load',
- 'did-frame-finish-load',
- 'did-start-loading',
- 'did-stop-loading',
- 'dom-ready',
- 'page-title-updated',
- 'page-favicon-updated',
- 'new-window',
- 'will-navigate',
- 'did-start-navigation',
- 'will-redirect',
- 'did-redirect-navigation',
- 'did-navigate',
- 'did-frame-navigate',
- 'did-navigate-in-page',
- 'will-prevent-unload',
- 'crashed',
- 'unresponsive',
- 'responsive',
- 'plugin-crashed',
- 'destroyed',
- 'before-input-event',
- 'enter-html-full-screen',
- 'leave-html-full-screen',
- 'zoom-changed',
- 'devtools-opened',
- 'devtools-closed',
- 'devtools-focused',
- 'certificate-error',
- 'select-client-certificate',
- 'login',
- 'found-in-page',
- 'media-started-playing',
- 'media-paused',
- 'did-change-theme-color',
- 'update-target-url',
- 'cursor-changed',
- 'context-menu',
- 'select-bluetooth-device',
- 'devtools-reload-page',
- 'will-attach-webview',
- 'did-attach-webview',
- 'console-message',
- 'preload-error'
- ]
- }
-
- static METHODS () {
- return [
- 'loadURL',
- 'loadFile',
- 'downloadURL',
- 'getURL',
- 'getTitle',
- 'isDestroyed',
- 'focus',
- 'isFocused',
- 'isLoading',
- 'isLoadingMainFrame',
- 'isWaitingForResponse',
- 'stop',
- 'reload',
- 'reloadIgnoringCache',
- 'canGoBack',
- 'canGoForward',
- 'canGoToOffset',
- 'clearHistory',
- 'goBack',
- 'goForward',
- 'goToIndex',
- 'goToOffset',
- 'isCrashed',
- 'setUserAgent',
- 'getUserAgent',
- 'insertCSS',
- 'removeInsertedCSS',
- 'executeJavaScript',
- 'executeJavaScriptInIsolatedWorld',
- 'setIgnoreMenuShortcuts',
- 'setAudioMuted',
- 'isAudioMuted',
- 'isCurrentlyAudible',
- 'setZoomFactor',
- 'getZoomFactor',
- 'setZoomLevel',
- 'getZoomLevel',
- 'setVisualZoomLevelLimits',
- 'undo',
- 'redo',
- 'cut',
- 'copy',
- 'copyImageAt',
- 'paste',
- 'pasteAndMatchStyle',
- 'delete',
- 'selectAll',
- 'unselect',
- 'replace',
- 'replaceMisspelling',
- 'insertText',
- 'findInPage',
- 'stopFindInPage',
- 'capturePage',
- 'isBeingCaptured',
- 'incrementCapturerCount',
- 'decrementCapturerCount',
- 'getPrinters',
- 'print',
- 'printToPDF',
- 'addWorkSpace',
- 'removeWorkSpace',
- 'setDevToolsWebContents',
- 'openDevTools',
- 'closeDevTools',
- 'isDevToolsOpened',
- 'isDevToolsFocused',
- 'toggleDevTools',
- 'inspectElement',
- 'inspectSharedWorker',
- 'inspectSharedWorkerById',
- 'getAllSharedWorkers',
- 'inspectServiceWorker',
- 'send',
- 'sendToFrame',
- 'enableDeviceEmulation',
- 'disableDeviceEmulation',
- 'sendInputEvent',
- 'beginFrameSubscription',
- 'endFrameSubscription',
- 'startDrag',
- 'savePage',
- 'showDefinitionForSelection',
- 'isOffscreen',
- 'startPainting',
- 'stopPainting',
- 'isPainting',
- 'setFrameRate',
- 'getFrameRate',
- 'invalidate',
- 'getWebRTCIPHandlingPolicy',
- 'setWebRTCIPHandlingPolicy',
- 'getOSProcessId',
- 'getProcessId',
- 'takeHeapSnapshot',
- 'setBackgroundThrottling',
- 'getType'
- ]
- }
-
- constructor () {
- super()
-
- this.view = null
-
- this.observer = new ResizeObserver(() => this.resizeView())
-
- for (const name of BrowserViewElement.METHODS()) {
- this[name] = (...args) => this.view.webContents[name](...args)
- }
-
- this.addEventListener('focus', () => {
- if (this.view) this.view.webContents.focus()
- })
-
- window.addEventListener('beforeunload', () => {
- if (this.view) this.view.destroy()
- })
- }
-
- connectedCallback () {
- this.observer.observe(this)
-
- const remote = require('electron').remote
- const currentWindow = remote.getCurrentWindow()
-
- const { BrowserView } = remote
- this.view = new BrowserView({
- webPreferences: {
- sandbox: true,
- safeDialogs: true,
- navigateOnDragDrop: true,
- enableRemoteModule: false,
- partition: this.getAttribute('partition')
- }
- })
-
- currentWindow.setBrowserView(this.view)
- this.resizeView()
-
- for (const event of BrowserViewElement.EVENTS()) {
- this.view.webContents.on(event, (...detail) => {
- this.dispatchEvent(new CustomEvent(event, { detail }))
- })
- }
-
- const src = this.getAttribute('src')
- if (src) this.loadURL(src)
- }
-
- disconnectedCallback () {
- this.observer.unobserve(this)
- this.view.destroy()
- this.view = null
- }
-
- static get observedAttributes () {
- return ['src']
- }
-
- attributeChangedCallback (name, oldValue, newValue) {
- if (!this.view) return
- this.loadURL(newValue)
- }
-
- resizeView () {
- if (!this.view) return
-
- const { x, y, width, height } = this.getBoundingClientRect()
-
- const rect = {
- x: Math.trunc(x),
- y: Math.trunc(y),
- width: Math.trunc(width),
- height: Math.trunc(height)
- }
-
- this.view.setBounds(rect)
- }
-
- get src () { return this.getAttribute('src') }
- set src (url) { this.setAttribute('src', url) }
-
- get audioMuted () { return this.view.webContents.audioMuted }
- set audioMuted (audioMuted) { this.view.webContents.audioMuted = audioMuted }
-
- get userAgent () { return this.view.webContents.userAgent }
- set userAgent (userAgent) { this.view.webContents.userAgent = userAgent }
-
- get zoomLevel () { return this.view.webContents.zoomLevel }
- set zoomLevel (zoomLevel) { this.view.webContents.zoomLevel = zoomLevel }
-
- get zoomFactor () { return this.view.webContents.zoomFactor }
- set zoomFactor (zoomFactor) { this.view.webContents.zoomFactor = zoomFactor }
-
- get frameRate () { return this.view.webContents.frameRate }
- set frameRate (frameRate) { this.view.webContents.frameRate = frameRate }
-
- get id () { return this.view.webContents.id }
-
- get session () { return this.view.webContents.session }
-
- get hostWebContents () { return this.view.webContents.hostWebContents }
-
- get devToolsWebContents () { return this.view.webContents.devToolsWebContents }
-
- get debugger () { return this.view.webContents.debugger }
-}
-
-customElements.define('browser-view', BrowserViewElement)
diff --git a/app/ui/index.html b/app/ui/index.html
index a4ee9fd..cacb1dd 100644
--- a/app/ui/index.html
+++ b/app/ui/index.html
@@ -11,18 +11,16 @@
@import url('style.css');
-
-
+
+
-
-
+
diff --git a/app/ui/omni-box.js b/app/ui/omni-box.js
index d9338c3..4046b4f 100644
--- a/app/ui/omni-box.js
+++ b/app/ui/omni-box.js
@@ -4,10 +4,6 @@ class OmniBox extends HTMLElement {
constructor () {
super()
this.firstLoad = true
-
- const { remote } = require('electron')
-
- this.history = remote.require('./history')
this.lastSearch = 0
}
@@ -32,6 +28,7 @@ class OmniBox extends HTMLElement {
this.input.addEventListener('focus', () => {
this.input.select()
})
+
this.form.addEventListener('submit', (e) => {
e.preventDefault(true)
@@ -138,10 +135,12 @@ class OmniBox extends HTMLElement {
return
}
- const results = await this.history.search(query)
+ this.dispatchEvent(new CustomEvent('search', { detail: { query, searchID } }))
+ }
+ async setSearchResults (results, query, searchID) {
if (this.lastSearch !== searchID) {
- return console.debug('Urlbar changed since query finished', this.input.value, query)
+ return console.debug('Urlbar changed since query finished', this.lastSearch, searchID, query)
}
const finalItems = []
diff --git a/app/ui/script.js b/app/ui/script.js
index 3e75390..2222df6 100644
--- a/app/ui/script.js
+++ b/app/ui/script.js
@@ -1,16 +1,10 @@
-const { pageContextMenu } = require('./context-menus')
-
const DEFAULT_PAGE = 'agregore://welcome'
const webview = $('#view')
const search = $('#search')
const find = $('#find')
-webview.addEventListener('dom-ready', () => {
- if (process.env.MODE === 'debug') {
- webview.openDevTools()
- }
-})
+const currentWindow = window.getCurrentWindow()
const pageTitle = $('title')
@@ -22,14 +16,18 @@ const rawFrame = searchParams.get('rawFrame') === 'true'
if (rawFrame) $('#top').classList.toggle('hidden', true)
-webview.src = toNavigate
+window.addEventListener('load', () => {
+ console.log('toNavigate', toNavigate)
+ currentWindow.loadURL(toNavigate)
+ webview.emitResize()
+})
search.addEventListener('back', () => {
- webview.goBack()
+ currentWindow.goBack()
})
search.addEventListener('forward', () => {
- webview.goForward()
+ currentWindow.goForward()
})
search.addEventListener('navigate', ({ detail }) => {
@@ -38,66 +36,69 @@ search.addEventListener('navigate', ({ detail }) => {
navigateTo(url)
})
-search.addEventListener('unfocus', () => {
- webview.focus()
- search.src = webview.getURL()
+search.addEventListener('unfocus', async () => {
+ await currentWindow.focus()
+ search.src = await webview.getURL()
})
-webview.addEventListener('did-start-navigation', ({ detail }) => {
- const url = detail[1]
- const isMainFrame = detail[3]
- if (!isMainFrame) return
- search.src = url
+search.addEventListener('search', async ({ detail }) => {
+ const { query, searchID } = detail
+
+ const results = await currentWindow.searchHistory(query, searchID)
+
+ search.setSearchResults(results, query, searchID)
})
-webview.addEventListener('did-navigate', updateButtons)
+webview.addEventListener('focus', () => {
+ currentWindow.focus()
+})
-webview.view.webContents.on('context-menu', pageContextMenu.bind(webview.view))
+webview.addEventListener('resize', ({ detail: rect }) => {
+ currentWindow.setBounds(rect)
+})
-webview.addEventListener('page-title-updated', ({ detail }) => {
- const title = detail[1]
- pageTitle.innerText = title + ' - Agregore Browser'
+currentWindow.on('navigating', (url) => {
+ search.src = url
})
-webview.addEventListener('new-window', ({ detail }) => {
- const options = detail[4]
+currentWindow.on('history-buttons-change', updateButtons)
- if (options && options.webContents) {
- options.webContents.on('context-menu', pageContextMenu.bind(webview.view))
- }
+currentWindow.on('page-title-updated', (title) => {
+ pageTitle.innerText = title + ' - Agregore Browser'
})
find.addEventListener('next', ({ detail }) => {
const { value, findNext } = detail
- webview.findInPage(value, { findNext })
+ currentWindow.findInPage(value, { findNext })
})
find.addEventListener('previous', ({ detail }) => {
const { value, findNext } = detail
- webview.findInPage(value, { forward: false, findNext })
+ currentWindow.findInPage(value, { forward: false, findNext })
})
find.addEventListener('hide', () => {
- webview.stopFindInPage('clearSelection')
+ currentWindow.stopFindInPage('clearSelection')
})
-function updateButtons () {
- search.setAttribute('back', webview.canGoBack() ? 'visible' : 'hidden')
- search.setAttribute('forward', webview.canGoForward() ? 'visible' : 'hidden')
+function updateButtons ({ canGoBack, canGoForward }) {
+ search.setAttribute('back', canGoBack ? 'visible' : 'hidden')
+ search.setAttribute('forward', canGoForward ? 'visible' : 'hidden')
}
function $ (query) {
return document.querySelector(query)
}
-function navigateTo (url) {
- if (webview.getURL() === url) {
+async function navigateTo (url) {
+ const currentURL = await currentWindow.getURL()
+ if (currentURL === url) {
console.log('Reloading')
- webview.reload()
+ currentWindow.reload()
} else {
- webview.src = url
- webview.focus()
+ currentWindow.loadURL(url)
+ currentWindow.focus()
}
}
diff --git a/app/ui/style.css b/app/ui/style.css
index 12ab1cb..abaefb2 100644
--- a/app/ui/style.css
+++ b/app/ui/style.css
@@ -41,7 +41,7 @@ omni-box {
.omni-box-header {
display: flex;
flex-direction: row;
- border: 2px solid var(--ag-color-purple);
+ border-bottom: 2px solid var(--ag-color-purple);
background: var(--ag-color-black);
color: var(--ag-color-white);
}
@@ -101,6 +101,7 @@ omni-box {
find-menu {
border: 2px solid var(--ag-color-purple);
+ border-top: none;
display: flex;
flex-direction: row;
background: var(--ag-color-black);
diff --git a/app/ui/tracked-box.js b/app/ui/tracked-box.js
new file mode 100644
index 0000000..72f20b3
--- /dev/null
+++ b/app/ui/tracked-box.js
@@ -0,0 +1,27 @@
+/* global HTMLElement, ResizeObserver, CustomEvent, customElements */
+
+class TrackedBox extends HTMLElement {
+ constructor () {
+ super()
+
+ this.observer = new ResizeObserver(() => this.emitResize())
+ }
+
+ connectedCallback () {
+ this.observer.observe(this)
+
+ this.emitResize()
+ }
+
+ disconnectedCallback () {
+ this.observer.unobserve(this)
+ }
+
+ emitResize () {
+ const { x, y, width, height } = this.getBoundingClientRect()
+
+ this.dispatchEvent(new CustomEvent('resize', { detail: { x, y, width, height } }))
+ }
+}
+
+customElements.define('tracked-box', TrackedBox)
diff --git a/app/window/index.js b/app/window/index.js
new file mode 100644
index 0000000..259de3f
--- /dev/null
+++ b/app/window/index.js
@@ -0,0 +1,277 @@
+const {
+ BrowserWindow,
+ BrowserView,
+ ipcMain,
+ app
+} = require('electron')
+const path = require('path')
+const EventEmitter = require('events')
+const fs = require('fs-extra')
+
+const MAIN_PAGE = path.resolve(__dirname, '../ui/index.html')
+const LOGO_FILE = path.join(__dirname, '../../build/icon.png')
+const PERSIST_FILE = path.join(app.getPath('userData'), 'lastOpened.json')
+
+const DEFAULT_PAGE = 'agregore://welcome'
+
+const IS_DEBUG = process.env.NODE_ENV === 'debug'
+
+const WINDOW_METHODS = [
+ 'goBack',
+ 'goForward',
+ 'reload',
+ 'focus',
+ 'loadURL',
+ 'getURL',
+ 'findInPage',
+ 'stopFindInPage',
+ 'setBounds',
+ 'searchHistory'
+]
+
+async function DEFAULT_SEARCH () {
+ return []
+}
+
+class WindowManager extends EventEmitter {
+ constructor ({
+ onSearch = DEFAULT_SEARCH,
+ persistTo = PERSIST_FILE
+ } = {}) {
+ super()
+ this.windows = new Set()
+ this.onSearch = onSearch
+ this.persistTo = persistTo
+
+ for (const method of WINDOW_METHODS) {
+ this.relayMethod(method)
+ }
+ }
+
+ open (opts = {}) {
+ const { onSearch } = this
+ const window = new Window({ ...opts, onSearch })
+
+ console.log('created window', window.id)
+ this.windows.add(window)
+ window.once('close', () => {
+ this.windows.delete(window)
+ this.emit('close', window)
+ })
+ this.emit('open', window)
+
+ window.load()
+
+ return window
+ }
+
+ relayMethod (name) {
+ ipcMain.handle(`agregore-window-${name}`, ({ sender }, ...args) => {
+ const { id } = sender
+ console.log('<-', id, name, '(', args, ')')
+ const window = this.get(id)
+ if (!window) return console.warn(`Got method ${name} from invalid frame ${id}`)
+
+ return window[name](...args)
+ })
+ }
+
+ get (id) {
+ for (const window of this.windows) {
+ if (window.id === id) return window
+ }
+ return null
+ }
+
+ get all () {
+ return [...this.windows.values()]
+ }
+
+ async saveOpened () {
+ let urls = await Promise.all(this.all.map(async (window) => {
+ const url = window.web.getURL()
+ const position = window.window.getPosition()
+ const size = window.window.getSize()
+
+ return { url, position, size }
+ }))
+
+ if (urls.length === 1) urls = []
+
+ fs.outputJsonSync(this.persistTo, urls)
+ }
+
+ async openSaved () {
+ const saved = await this.loadSaved()
+
+ return Promise.all(saved.map((info) => {
+ console.log('About to open', info)
+ const options = {}
+
+ if (typeof info === 'string') {
+ options.url = info
+ } else {
+ const { url, position, size } = info
+
+ options.url = url
+
+ if (position) {
+ const [x, y] = position
+ options.x = x
+ options.y = y
+ }
+
+ if (size) {
+ const [width, height] = size
+ options.width = width
+ options.height = height
+ }
+ }
+
+ return this.open(options)
+ }))
+ }
+
+ async loadSaved () {
+ try {
+ const infos = await fs.readJson(this.persistTo)
+ return infos
+ } catch (e) {
+ console.error('Error loading saved windows', e.stack)
+ return []
+ }
+ }
+}
+
+class Window extends EventEmitter {
+ constructor ({
+ url = DEFAULT_PAGE,
+ rawFrame = false,
+ onSearch,
+ ...opts
+ } = {}) {
+ super()
+
+ this.onSearch = onSearch
+
+ this.window = new BrowserWindow({
+ autoHideMenuBar: true,
+ webPreferences: {
+ // partition: 'persist:web-content',
+ nodeIntegration: true,
+ webviewTag: false,
+ contextIsolation: false
+ },
+ show: false,
+ icon: LOGO_FILE,
+ ...opts
+ })
+
+ this.view = new BrowserView({
+ webPreferences: {
+ partition: 'persist:web-content',
+ nodeIntegration: false,
+ sandbox: true,
+ webviewTag: false,
+ contextIsolation: true
+ }
+ })
+ this.window.setBrowserView(this.view)
+
+ this.web.on('did-navigate', (event, url, isMainFrame) => {
+ console.log('Navigating', url, isMainFrame)
+ if (!isMainFrame) return
+ this.send('navigating', url)
+ })
+ this.web.on('did-navigate', () => {
+ const canGoBack = this.web.canGoBack()
+ const canGoForward = this.web.canGoForward()
+
+ this.send('history-buttons-change', { canGoBack, canGoForward })
+ })
+ this.web.on('page-title-updated', (event, title) => {
+ this.send('page-title-updated', title)
+ })
+ this.window.once('ready-to-show', () => this.window.show())
+ this.window.on('close', () => {
+ if (this.view.destroy) this.view.destroy()
+ this.emit('close')
+ })
+
+ const toLoad = new URL(MAIN_PAGE, 'file:')
+
+ if (url) toLoad.searchParams.set('url', url)
+ if (rawFrame) toLoad.searchParams.set('rawFrame', 'true')
+
+ this.toLoad = toLoad.href
+
+ if (IS_DEBUG) {
+ // this.web.openDevTools()
+ this.window.webContents.openDevTools()
+ }
+ }
+
+ load () {
+ return this.window.loadURL(this.toLoad)
+ }
+
+ async goBack () {
+ return this.web.goBack()
+ }
+
+ async goForward () {
+ return this.web.goForward()
+ }
+
+ async reload () {
+ return this.web.reload()
+ }
+
+ async focus () {
+ return this.web.focus()
+ }
+
+ async loadURL (url) {
+ return this.web.loadURL(url)
+ }
+
+ async getURL () {
+ return this.web.getURL()
+ }
+
+ async findInPage (value, opts) {
+ return this.web.findInPage(value, opts)
+ }
+
+ async stopFindInPage () {
+ return this.web.stopFindInPage('clearSelection')
+ }
+
+ async searchHistory (...args) {
+ return this.onSearch(...args)
+ }
+
+ async setBounds (rect) {
+ return this.view.setBounds(rect)
+ }
+
+ send (name, ...args) {
+ this.emit(name, ...args)
+ console.log('->', this.id, name, '(', args, ')')
+ this.window.webContents.send(`agregore-window-${name}`, ...args)
+ }
+
+ get web () {
+ return this.view.webContents
+ }
+
+ get webContents () {
+ return this.window.webContents
+ }
+
+ get id () {
+ return this.window.webContents.id
+ }
+}
+
+module.exports = { WindowManager, Window }
diff --git a/app/windows.js b/app/windows.js
deleted file mode 100644
index 8b5ccd4..0000000
--- a/app/windows.js
+++ /dev/null
@@ -1,96 +0,0 @@
-const { app } = require('electron')
-const { BrowserWindow } = require('electron')
-const { resolve } = require('path')
-const { headerContextMenu } = require('./ui/context-menus')
-const fs = require('fs-extra')
-const path = require('path')
-
-const MAIN_PAGE = resolve(__dirname, './ui/index.html')
-const PERSIST_FILE = path.join(app.getPath('userData'), 'lastOpened.json')
-const LOGO_FILE = path.join(__dirname, '../build/icon.png')
-
-module.exports = {
- createWindow,
- loadFromHistory,
- saveOpen
-}
-
-const openWindows = new Set()
-
-function createWindow (url, options = {}) {
- // Create the browser window.
- const win = new BrowserWindow({
- autoHideMenuBar: true,
- webPreferences: {
- session: 'persist:web-content',
- nodeIntegration: true,
- webviewTag: false
- },
- icon: LOGO_FILE,
- show: false,
- ...options
- })
-
- win.once('ready-to-show', () => win.show())
-
- win.webContents.on('context-menu', headerContextMenu.bind(win))
-
- const { rawFrame } = options
-
- const toLoad = new URL(MAIN_PAGE, 'file:')
-
- if (url) toLoad.searchParams.set('url', url)
- if (rawFrame) toLoad.searchParams.set('rawFrame', 'true')
-
- // and load the index.html of the app.
- win.loadURL(toLoad.href)
-
- // Open the DevTools.
- if (process.env.MODE === 'debug') {
- win.webContents.openDevTools()
- }
-
- openWindows.add(win)
-
- win.once('closed', () => {
- openWindows.delete(win)
- })
-}
-
-function saveOpen (file = PERSIST_FILE) {
- const urls = getToSave()
-
- fs.outputJsonSync(file, urls)
-}
-
-function getToSave () {
- const currentlyOpen = [...openWindows]
-
- const urls = currentlyOpen.map((win) => {
- const view = win.getBrowserView() || win
- return view.webContents.getURL()
- })
-
- if (urls.length === 1) return []
- return urls
-}
-
-async function loadFromHistory (file = PERSIST_FILE) {
- const urls = await getHistory(file)
-
- for (const url of urls) {
- createWindow(url)
- }
-
- return urls
-}
-
-async function getHistory (file = PERSIST_FILE) {
- try {
- const urls = await fs.readJson(file)
- return urls
- } catch (e) {
- console.error(e.stack)
- return []
- }
-}
diff --git a/package.json b/package.json
index eed509e..0915c03 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"scripts": {
"test": "npm run lint",
"start": "electron .",
- "debug": "env MODE=debug electron .",
+ "debug": "env NODE_ENV=debug electron --trace-uncaught .",
"build": "electron-builder build --publish never",
"build-all": "electron-builder build -mwl",
"lint": "standard --fix",
@@ -89,14 +89,14 @@
},
"homepage": "https://github.com/RangerMauve/agregore-browser#readme",
"devDependencies": {
- "electron": "^9.1.0",
+ "electron": "11.0.0-beta.1",
"electron-builder": "^21",
"electron-rebuild": "^1.11.0",
"standard": "^14.3.4"
},
"dependencies": {
"@geut/hyperdrive-promise": "^3.0.1",
- "dat-fetch": "^5.0.0",
+ "dat-fetch": "^5.0.1",
"dat-sdk": "^2.1.0",
"dat-sdk-old": "^1.0.0",
"electron-extensions": "^6.0.4",
@@ -105,8 +105,8 @@
"gemini-to-html": "^1.0.0",
"ipfs": "^0.46.0",
"mime": "^2.4.6",
- "whatwg-mimetype": "https://github.com/jsdom/whatwg-mimetype#v2.3.0",
"rc": "^1.2.8",
- "scoped-fs": "^1.4.1"
+ "scoped-fs": "^1.4.1",
+ "whatwg-mimetype": "https://github.com/jsdom/whatwg-mimetype#v2.3.0"
}
}
diff --git a/yarn.lock b/yarn.lock
index d45c68a..317b9eb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2320,10 +2320,10 @@ dat-encoding@^5.0.1:
dependencies:
safe-buffer "^5.0.1"
-dat-fetch@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/dat-fetch/-/dat-fetch-5.0.0.tgz#81a890d835d23ebcb9bc1284ea745db3f68b4901"
- integrity sha512-ir0hVJwRnebsolTWlKDGFJytcgxcrMPXlqdeWNLFNe9sI7Lv7JQOcGrczCcqHpHRjIs2wF8ZNk6dwt/lWTDV2A==
+dat-fetch@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/dat-fetch/-/dat-fetch-5.0.1.tgz#b9fe6f47bd35002219c4de2b8a4939fa2370cf5e"
+ integrity sha512-T5+LY9nE/if3dCBEHVebomw+QS4dlD7wdUdpIi21ka0W24vDnbfWUOwIoKtTSFRBBDNelDBWZlxAKw65VpA+bA==
dependencies:
concat-stream "^2.0.0"
end-of-stream-promise "^1.0.0"
@@ -3046,10 +3046,10 @@ electron-rebuild@^1.11.0:
spawn-rx "^3.0.0"
yargs "^14.2.0"
-electron@^9.1.0:
- version "9.2.0"
- resolved "https://registry.yarnpkg.com/electron/-/electron-9.2.0.tgz#d9fc8c8c9e5109669c366bd7b9ba83b06095d7a4"
- integrity sha512-4ecZ3rcGg//Gk4fAK3Jo61T+uh36JhU6HHR/PTujQqQiBw1g4tNPd4R2hGGth2d+7FkRIs5GdRNef7h64fQEMw==
+electron@11.0.0-beta.1:
+ version "11.0.0-beta.1"
+ resolved "https://registry.yarnpkg.com/electron/-/electron-11.0.0-beta.1.tgz#f4a3b3e0783c7ef2c70a4e5232e9cc0ef8f98974"
+ integrity sha512-+dYLXqFmLWOCSlwfzMec4CpcpHenpB9cjWRiiKc2CDwc3Esp5fZ+dU/nX/kIbdrlj7FaOBn0Wf6RjCSif4ebmg==
dependencies:
"@electron/get" "^1.0.1"
"@types/node" "^12.0.12"