From 1893d16c69f06f72c30dd14e49b5a17722490ee0 Mon Sep 17 00:00:00 2001 From: kPherox Date: Tue, 9 Apr 2019 00:06:28 +0900 Subject: [PATCH] Fix some error background.ts convert to typescript class --- package-lock.json | 6 + package.json | 1 + src/background.ts | 543 ++++++++++++++++++++++++++-------------------- tsconfig.json | 1 + 4 files changed, 315 insertions(+), 236 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb7953a9..fea0acaf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -920,6 +920,12 @@ "@types/node": "*" } }, + "@types/lodash": { + "version": "4.14.123", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.123.tgz", + "integrity": "sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", diff --git a/package.json b/package.json index 98875483..5c4d30ed 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "vue-property-decorator": "^7.0.0" }, "devDependencies": { + "@types/lodash": "^4.14.123", "@vue/cli-plugin-babel": "^3.5.0", "@vue/cli-plugin-eslint": "^3.5.0", "@vue/cli-service": "^3.5.0", diff --git a/src/background.ts b/src/background.ts index 778d948f..3ed48d43 100644 --- a/src/background.ts +++ b/src/background.ts @@ -1,262 +1,333 @@ 'use strict' -import path from 'path' -import pick from 'lodash/pick' +import * as path from 'path' +import { pick } from 'lodash' import { - app, - protocol, - shell, - BrowserWindow, - Menu + app, + ipcMain, + protocol, + shell, + BrowserWindow, + Menu, } from 'electron' +// Electron types +import { + App, + BrowserWindowConstructorOptions, + Event, + MenuItemConstructorOptions, +} from 'electron' + import ContextMenu from 'electron-context-menu' import { - createProtocol, - installVueDevtools + createProtocol, + installVueDevtools } from 'vue-cli-plugin-electron-builder/lib' -import localShortcut from 'electron-localshortcut' +// tslint:disable-next-line:no-var-requires +const localShortcut = require('electron-localshortcut') +export type PackageJson = typeof import('../package.json'); import { bugs, homepage } from '../package.json' -import thedeskInfo from '../info.json' +import TheDeskInfo from '../info.json' +export type TheDeskInfoObject = typeof TheDeskInfo; -global.TheDeskInfo = JSON.stringify(Object.assign({ - productName: app.getName(), - homePage: homepage, - versions: Object.assign(pick(process.versions, ["chrome","electron","node"]), {internal: app.getVersion()}), -}, thedeskInfo)) +declare const __static: string; + +ipcMain.on('thedesk-info', (event: Event) => { + event.returnValue = Object.assign({ + productName: app.getName(), + homePage: homepage, + versions: Object.assign(pick(process.versions, ["chrome","electron","node"]), {internal: app.getVersion()}), + }, TheDeskInfo) +}) const isDevelopment = process.env.NODE_ENV !== 'production' -// イベントリスナや`createWindow`関数が参照するグローバル変数 -let createdAppProtocol = false - , windows = {} +if (isDevelopment) { + if (process.platform === 'win32') { + process.on('message', data => { + if (data === 'graceful-exit') { + app.quit() + } + }) + } else { + process.on('SIGTERM', () => { + app.quit() + }) + } +} -ContextMenu() - -// Standard schemeはreadyの前に登録する必要がある protocol.registerStandardSchemes(['app'], { secure: true }) -// Windowを作る -async function createWindow(windowName, loadPath, windowOptions, singleton, lastAction, openDevTools) { - if (typeof windows[windowName] !== 'undefined') { - windows[windowName].show() - return - } - - // 引数のバリデーション - if (typeof windowOptions !== 'object') windowOptions = {} - if (typeof lastAction !== 'function') lastAction = () => {} - - let win = new BrowserWindow(windowOptions) - - // ページの表示が完了するまで非表示にする - win.hide() - win.webContents.on('did-finish-load', () => { - windows[windowName].show() - }) - - win.on('closed', () => { - windows[windowName] = undefined - }) - - let openUrl = (event, url) => { - if (url === process.env.WEBPACK_DEV_SERVER_URL + loadPath) { - return - } - event.preventDefault() - shell.openExternal(url, { - activate: false - }, (err) => { - if (err) console.log(err) - }) - } - win.webContents.on('will-navigate', openUrl) - win.webContents.on('new-window', openUrl) - - if (process.env.WEBPACK_DEV_SERVER_URL) { - // `electron:serve`で起動した時の読み込み - win.loadURL(process.env.WEBPACK_DEV_SERVER_URL + loadPath) - } else { - // ビルドしたアプリでの読み込み - if (!createdAppProtocol) { - createProtocol('app') - createdAppProtocol = true - } - win.loadURL(`app://./${loadPath}`) - } - - if (isDevelopment && openDevTools) win.webContents.openDevTools() - - lastAction(win) - - windows[windowName] = win +interface CreateWindowOptions { + windowName: string + loadPath: string + windowOptions?: BrowserWindowConstructorOptions + singleton?: boolean + lastAction?: (win: BrowserWindow) => void + openDevTools?: boolean } -function openMainWindow() { - const winOpts = { - icon: path.join(__static, 'icon.png'), - width: 800, - height: 600, - autoHideMenuBar: true, - } - createWindow('main', 'index.html', winOpts, true, (win) => { - localShortcut.register(win, 'F5', () => windows.main.reload()) - }, !process.env.IS_TEST) -} +class Application { + public app: App; + public windows: { [key: string]: BrowserWindow } = {}; -// Quit when all windows are closed. -app.on('window-all-closed', () => { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit() - } -}) - -app.on('activate', () => { - // On macOS it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (typeof windows.main === 'undefined') { - openMainWindow() - } -}) - -// 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. -app.on('ready', async () => { - if (isDevelopment && !process.env.IS_TEST) { - // Install Vue Devtools - try { - await installVueDevtools() - } catch (e) { - console.error('Vue Devtools failed to install:', e.toString()) + constructor(app: App) { + this.app = app; + ContextMenu() + this.app.on('window-all-closed', () => this.onWindowAllClosed()) + this.app.on('ready', () => this.onReady()); + this.app.on('activate', () => this.onActivated()); } - } - openMainWindow() -}) -// Exit cleanly on request from parent process in development mode. -if (isDevelopment) { - if (process.platform === 'win32') { - process.on('message', data => { - if (data === 'graceful-exit') { - app.quit() - } - }) - } else { - process.on('SIGTERM', () => { - app.quit() - }) - } -} - -const template = [ - { - label: app.getName(), - submenu: [ - { - label: process.platform !== 'darwin' ? 'About' : `About ${app.getName()}`, - click: () => { - const winOpts = { - width: 296, - height: 432, - resizable: false, - minimizable: false, - maximizable: false, - fullscreenable: false, - autoHideMenuBar: true, - titleBarStyle: 'hiddenInset', - } - createWindow('about', 'about.html', winOpts, true, (win) => { - win.setMenuBarVisibility(false) - win.webContents.on('before-input-event', (event, input) => { - if (typeof windows.about !== 'undefined') - windows.about.webContents.setIgnoreMenuShortcuts(input.key !== "Escape") - }) - localShortcut.register(win, 'Esc', () => windows.about.destroy()) - }) + private onWindowAllClosed() { + if (process.platform !== 'darwin') { + this.app.quit() } - }, - ] - }, - { - label: 'Edit', - submenu: [ - { role: 'undo' }, - { role: 'redo' }, - { type: 'separator' }, - { role: 'cut' }, - { role: 'copy' }, - { role: 'paste' }, - { role: 'pasteandmatchstyle' }, - { role: 'delete' }, - { role: 'selectall' }, - ] - }, - { - label: 'View', - submenu: [ - { role: 'reload' }, - { role: 'forcereload' }, - { role: 'toggledevtools' }, - { type: 'separator' }, - { role: 'togglefullscreen' }, - ] - }, - { - role: 'Window', - submenu: [ - { role: 'minimize' }, - { role: 'close' }, - ] - }, - { - role: 'help', - submenu: [ - { - label: 'Report an issue', - click: () => shell.openExternal(`${bugs.url}/new`), - }, - { - label: 'Learn More', - click: () => shell.openExternal(thedeskInfo.documentURL), - } - ] - } -] - -if (process.platform === 'darwin') { - template[0].submenu.push( - { type: 'separator' }, - { role: 'services' }, - { type: 'separator' }, - { role: 'hide' }, - { role: 'hideothers' }, - { role: 'unhide' }, - { type: 'separator' }, - { role: 'quit' }, - ) - - template[1].submenu.push( - { type: 'separator' }, - { - label: 'Speech', - submenu: [ - { role: 'startspeaking' }, - { role: 'stopspeaking' }, - ] } - ) - template[3].submenu = [ - { role: 'close' }, - { role: 'minimize' }, - { role: 'zoom' }, - { type: 'separator' }, - { role: 'front' }, - ] + private async onReady() { + if (isDevelopment && !process.env.IS_TEST) { + // Install Vue Devtools + try { + await installVueDevtools() + } catch (e) { + //console.error('Vue Devtools failed to install:', e.toString()) + } + } + if (!process.env.WEBPACK_DEV_SERVER_URL) createProtocol('app') + this.openMainWindow() + } + + private onActivated() { + if (typeof this.windows.main === 'undefined') { + this.openMainWindow() + } + } + + public openMainWindow() { + const opts: CreateWindowOptions = { + windowName: 'main', + loadPath: 'index.html', + windowOptions: { + icon: path.join(__static, 'icon.png'), + width: 800, + height: 600, + autoHideMenuBar: true, + }, + singleton: true, + lastAction: (win) => { + localShortcut.register(win, 'F5', () => this.windows.main.reload()) + }, + openDevTools: !process.env.IS_TEST + } + this.createWindow(opts) + } + + public openAboutWindow() { + const opts: CreateWindowOptions = { + windowName: 'about', + loadPath: 'about.html', + windowOptions: { + width: 296, + height: 432, + resizable: false, + minimizable: false, + maximizable: false, + fullscreenable: false, + autoHideMenuBar: true, + titleBarStyle: 'hiddenInset', + }, + singleton: true, + lastAction: (win) => { + win.setMenuBarVisibility(false) + win.webContents.on('before-input-event', (event, input) => { + if (typeof this.windows.about !== 'undefined') + this.windows.about.webContents.setIgnoreMenuShortcuts((input.meta || input.control) && input.key !== "R" || input.key === "F5") + }) + localShortcut.register(win, 'Esc', () => this.windows.about.destroy()) + }, + openDevTools: !process.env.IS_TEST + } + this.createWindow(opts) + } + + private async createWindow(options: CreateWindowOptions) { + if (typeof this.windows[options.windowName] !== 'undefined') { + this.windows[options.windowName].show() + return + } + let win = new BrowserWindow(options.windowOptions) + win.hide() + win.webContents.on('did-finish-load', () => { + this.windows[options.windowName].show() + }) + + win.on('closed', () => { + delete this.windows[options.windowName] + }) + + let openUrl = (event: Event, url: string) => { + if (url === process.env.WEBPACK_DEV_SERVER_URL + options.loadPath) { + return + } + event.preventDefault() + shell.openExternal(url, { + activate: false + }, (err) => { + //if (err) console.log(err) + }) + } + win.webContents.on('will-navigate', openUrl) + win.webContents.on('new-window', openUrl) + + if (process.env.WEBPACK_DEV_SERVER_URL) { + // `electron:serve`で起動した時の読み込み + win.loadURL(process.env.WEBPACK_DEV_SERVER_URL + options.loadPath) + } else { + // ビルドしたアプリでの読み込み + win.loadURL(`app://./${options.loadPath}`) + } + + if (isDevelopment && options.openDevTools) win.webContents.openDevTools() + + if (typeof options.lastAction === 'function') options.lastAction(win) + + this.windows[options.windowName] = win + } } -const menu = Menu.buildFromTemplate(template) -Menu.setApplicationMenu(menu) +class ApplicationMenu { + private app: Application; + + // Mac only menu. prefix `macOnly`. First Item always separator + private macOnlyAppMenu: MenuItemConstructorOptions[] = [ + { type: 'separator' }, + { role: 'services' }, + { type: 'separator' }, + { role: 'hide' }, + { role: 'hideOthers' }, + { role: 'unhide' }, + ]; + private macOnlyEditMenu: MenuItemConstructorOptions[] = [ + { type: 'separator' }, + { + label: 'Speech', + submenu: [ + { role: 'startspeaking' }, + { role: 'stopspeaking' }, + ] + } + ]; + + private get aboutMenuItem(): MenuItemConstructorOptions { + return { + label: process.platform !== 'darwin' ? 'About' : `About ${this.app.app.getName()}`, + click: () => this.app.openAboutWindow(), + } + } + + constructor(app: Application) { + this.app = app; + } + + public setApplicationMenu() { + const menu = Menu.buildFromTemplate(this.buildTemplate(process.platform === 'darwin')) + Menu.setApplicationMenu(menu) + } + + private buildTemplate(isMac: boolean): MenuItemConstructorOptions[] { + return [ + this.AppMenu(isMac), + this.EditMenu(isMac), + this.ViewMenu(), + this.WindowMenu(isMac), + this.HelpMenu(), + ] + } + + private AppMenu(isMac: boolean): MenuItemConstructorOptions { + let appMenu: MenuItemConstructorOptions[] = [ + this.aboutMenuItem, + ...(isMac ? this.macOnlyAppMenu : []), + { type: 'separator' }, + { role: 'quit' }, + ] + return { + label: this.app.app.getName(), + submenu: appMenu, + } + } + + private EditMenu(isMac: boolean): MenuItemConstructorOptions { + let editMenu: MenuItemConstructorOptions[] = [ + { role: 'undo' }, + { role: 'redo' }, + { type: 'separator' }, + { role: 'cut' }, + { role: 'copy' }, + { role: 'paste' }, + { role: 'pasteandmatchstyle' }, + { role: 'delete' }, + { role: 'selectall' }, + ...(isMac ? this.macOnlyEditMenu : []), + ] + return { + label: 'Edit', + submenu: editMenu, + } + } + + private ViewMenu(): MenuItemConstructorOptions { + let viewMenu: MenuItemConstructorOptions[] = [ + { role: 'reload' }, + { role: 'forcereload' }, + { role: 'toggledevtools' }, + { type: 'separator' }, + { role: 'togglefullscreen' }, + ] + return { + label: 'View', + submenu: viewMenu + } + } + + private WindowMenu(isMac: boolean): MenuItemConstructorOptions { + let windowMenu: MenuItemConstructorOptions[] = isMac ? [ + { role: 'close' }, + { role: 'minimize' }, + { role: 'zoom' }, + { type: 'separator' }, + { role: 'front' }, + ] : [ + { role: 'minimize' }, + { role: 'close' }, + ] + return { + label: 'Window', + submenu: windowMenu, + } + } + + private HelpMenu(): MenuItemConstructorOptions { + let helpMenu: MenuItemConstructorOptions[] = [ + { + label: 'Report an issue', + click: () => shell.openExternal(`${bugs.url}/new`), + }, + { + label: 'Learn More', + click: () => shell.openExternal(TheDeskInfo.documentURL), + } + ] + return { + label: 'Help', + submenu: helpMenu, + } + } +} + +const TheDeskVueApp: Application = new Application(app) +const MainMenu: ApplicationMenu = new ApplicationMenu(TheDeskVueApp) +MainMenu.setApplicationMenu() + diff --git a/tsconfig.json b/tsconfig.json index b57578e5..b7120617 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "importHelpers": true, "moduleResolution": "node", "experimentalDecorators": true, + "resolveJsonModule": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "sourceMap": true,