This commit is contained in:
Eugene Pankov
2017-05-01 13:35:26 +02:00
parent 8837173b1c
commit 889a60ba3b
62 changed files with 251 additions and 384 deletions

View File

@@ -14,7 +14,6 @@ import { ThemesService } from '../services/themes.service'
import { AppService, IToolbarButton, ToolbarButtonProvider } from '../api'
@Component({
selector: 'app-root',
template: require('./appRoot.component.pug'),
@@ -46,7 +45,7 @@ export class AppRootComponent {
Platform = Platform
private logger: Logger
constructor(
constructor (
private docking: DockingService,
private electron: ElectronService,
private tabRecovery: TabRecoveryService,
@@ -76,16 +75,16 @@ export class AppRootComponent {
}
}
if (this.app.activeTab) {
if (hotkey == 'close-tab') {
if (hotkey === 'close-tab') {
this.app.closeTab(this.app.activeTab)
}
if (hotkey == 'toggle-last-tab') {
if (hotkey === 'toggle-last-tab') {
this.app.toggleLastTab()
}
if (hotkey == 'next-tab') {
if (hotkey === 'next-tab') {
this.app.nextTab()
}
if (hotkey == 'previous-tab') {
if (hotkey === 'previous-tab') {
this.app.previousTab()
}
}
@@ -113,7 +112,7 @@ export class AppRootComponent {
// unfocused, invisible
this.electron.app.window.show()
} else {
if (this.config.store.appearance.dock == 'off') {
if (this.config.store.appearance.dock === 'off') {
// not docked, visible
setTimeout(() => {
this.electron.app.window.focus()
@@ -134,7 +133,7 @@ export class AppRootComponent {
await this.tabRecovery.recoverTabs()
this.tabRecovery.saveTabs(this.app.tabs)
if (this.app.tabs.length == 0) {
if (this.app.tabs.length === 0) {
this.app.openDefaultTab()
}
}

View File

@@ -1,8 +1,8 @@
import { Subject, BehaviorSubject } from 'rxjs'
import { ViewRef } from '@angular/core'
export abstract class BaseTabComponent {
private static lastTabID = 0
id: number
title$ = new BehaviorSubject<string>(null)
scrollable: boolean
@@ -11,7 +11,6 @@ export abstract class BaseTabComponent {
blurred$ = new Subject<void>()
hasFocus = false
hostView: ViewRef
private static lastTabID = 0
constructor () {
this.id = BaseTabComponent.lastTabID++

View File

@@ -3,12 +3,12 @@ import { ElectronService } from '../services/electron.service'
import { IToolbarButton, ToolbarButtonProvider } from '../api'
@Component({
selector: 'start-page',
template: require('./startPage.component.pug'),
styles: [require('./startPage.component.scss')],
selector: 'start-page',
template: require('./startPage.component.pug'),
styles: [require('./startPage.component.scss')],
})
export class StartPageComponent {
constructor(
constructor (
private electron: ElectronService,
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
) { }

View File

@@ -2,9 +2,9 @@ import { Component, Input, Output, EventEmitter, HostBinding } from '@angular/co
import { BaseTabComponent } from '../components/baseTab.component'
@Component({
selector: 'tab-header',
template: require('./tabHeader.component.pug'),
styles: [require('./tabHeader.component.scss')],
selector: 'tab-header',
template: require('./tabHeader.component.pug'),
styles: [require('./tabHeader.component.scss')],
})
export class TabHeaderComponent {
@Input() index: number

View File

@@ -1,9 +1,8 @@
import { Component } from '@angular/core'
@Component({
selector: 'title-bar',
template: require('./titleBar.component.pug'),
styles: [require('./titleBar.component.scss')],
selector: 'title-bar',
template: require('./titleBar.component.pug'),
styles: [require('./titleBar.component.scss')],
})
export class TitleBarComponent {
}
export class TitleBarComponent { }

View File

@@ -1,7 +1,6 @@
import { ConfigProvider } from './api/configProvider'
import { Platform } from './services/hostApp.service'
export class CoreConfigProvider extends ConfigProvider {
platformDefaults = {
[Platform.macOS]: require('./configDefaults.macos.yaml'),

View File

@@ -13,7 +13,6 @@ import { HostAppService } from './services/hostApp.service'
import { LogService } from './services/log.service'
import { HotkeysService, AppHotkeyProvider } from './services/hotkeys.service'
import { NotifyService } from './services/notify.service'
import { PluginsService } from './services/plugins.service'
import { QuitterService } from './services/quitter.service'
import { DockingService } from './services/docking.service'
import { TabRecoveryService } from './services/tabRecovery.service'
@@ -43,7 +42,6 @@ const PROVIDERS = [
HotkeysService,
LogService,
NotifyService,
PluginsService,
TabRecoveryService,
ThemesService,
QuitterService,
@@ -52,7 +50,6 @@ const PROVIDERS = [
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
]
@NgModule({
imports: [
BrowserModule,
@@ -73,7 +70,7 @@ const PROVIDERS = [
],
})
export default class AppModule {
static forRoot(): ModuleWithProviders {
static forRoot (): ModuleWithProviders {
return {
ngModule: AppModule,
providers: PROVIDERS,

View File

@@ -6,7 +6,6 @@ import { Logger, LogService } from '../services/log.service'
export declare type TabComponentType = new (...args: any[]) => BaseTabComponent
@Injectable()
export class AppService {
tabs: BaseTabComponent[] = []
@@ -44,7 +43,7 @@ export class AppService {
}
selectTab (tab: BaseTabComponent) {
if (this.activeTab == tab) {
if (this.activeTab === tab) {
return
}
if (this.tabs.includes(this.activeTab)) {
@@ -85,12 +84,9 @@ export class AppService {
closeTab (tab: BaseTabComponent) {
tab.destroy()
/* if (tab.session) {
this.sessions.destroySession(tab.session)
} */
let newIndex = Math.max(0, this.tabs.indexOf(tab) - 1)
this.tabs = this.tabs.filter((x) => x != tab)
if (tab == this.activeTab) {
this.tabs = this.tabs.filter((x) => x !== tab)
if (tab === this.activeTab) {
this.selectTab(this.tabs[newIndex])
}
this.tabsChanged$.next()

View File

@@ -6,6 +6,7 @@ import { ConfigProvider } from '../api/configProvider'
import { ElectronService } from './electron.service'
import { HostAppService } from './hostApp.service'
const configMerge = (a, b) => require('deepmerge')(a, b, { arrayMerge: (_d, s) => s })
export class ConfigProxy {
constructor (real: any, defaults: any) {
@@ -47,10 +48,6 @@ export class ConfigProxy {
}
}
const configMerge = (a, b) => require('deepmerge')(a, b, { arrayMerge: (_d, s) => s })
@Injectable()
export class ConfigService {
store: any

View File

@@ -3,7 +3,6 @@ import { ConfigService } from '../services/config.service'
import { ElectronService } from '../services/electron.service'
import { HostAppService } from '../services/hostApp.service'
export interface IScreen {
id: string
name: string
@@ -11,7 +10,7 @@ export interface IScreen {
@Injectable()
export class DockingService {
constructor(
constructor (
private electron: ElectronService,
private config: ConfigService,
private hostApp: HostAppService,
@@ -19,7 +18,7 @@ export class DockingService {
dock () {
let display = this.electron.screen.getAllDisplays()
.filter((x) => x.id == this.config.store.appearance.dockScreen)[0]
.filter((x) => x.id === this.config.store.appearance.dockScreen)[0]
if (!display) {
display = this.getCurrentScreen()
}
@@ -28,31 +27,30 @@ export class DockingService {
let newBounds: Electron.Rectangle = { x: 0, y: 0, width: 0, height: 0 }
let fill = this.config.store.appearance.dockFill
if (dockSide == 'off') {
if (dockSide === 'off') {
this.hostApp.setAlwaysOnTop(false)
return
}
if (dockSide == 'left' || dockSide == 'right') {
if (dockSide === 'left' || dockSide === 'right') {
newBounds.width = Math.round(fill * display.bounds.width)
newBounds.height = display.bounds.height
}
if (dockSide == 'top' || dockSide == 'bottom') {
if (dockSide === 'top' || dockSide === 'bottom') {
newBounds.width = display.bounds.width
newBounds.height = Math.round(fill * display.bounds.height)
}
if (dockSide == 'right') {
if (dockSide === 'right') {
newBounds.x = display.bounds.x + display.bounds.width * (1.0 - fill)
} else {
newBounds.x = display.bounds.x
}
if (dockSide == 'bottom') {
if (dockSide === 'bottom') {
newBounds.y = display.bounds.y + display.bounds.height * (1.0 - fill)
} else {
newBounds.y = display.bounds.y
}
this.hostApp.setAlwaysOnTop(true)
//this.hostApp.unmaximize()
setImmediate(() => {
this.hostApp.setBounds(newBounds)
})

View File

@@ -2,15 +2,17 @@ import { Injectable } from '@angular/core'
@Injectable()
export class ElectronService {
constructor() {
if (process.env.TEST_ENV) {
this.initTest()
} else {
this.init()
}
}
app: any
ipcRenderer: any
shell: any
dialog: any
clipboard: any
globalShortcut: any
screen: any
private electron: any
private remoteElectron: any
init() {
constructor () {
this.electron = require('electron')
this.remoteElectron = this.remoteRequire('electron')
this.app = this.remoteElectron.app
@@ -22,21 +24,7 @@ export class ElectronService {
this.globalShortcut = this.remoteElectron.globalShortcut
}
initTest() {
;
}
remoteRequire(name: string): any {
remoteRequire (name: string): any {
return this.electron.remote.require(name)
}
app: any
ipcRenderer: any
shell: any
dialog: any
clipboard: any
globalShortcut: any
screen: any
private electron: any
private remoteElectron: any
}

View File

@@ -6,13 +6,18 @@ export enum Platform {
Linux, macOS, Windows,
}
@Injectable()
export class HostAppService {
platform: Platform
nodePlatform: string
quitRequested = new EventEmitter<any>()
ready = new EventEmitter<any>()
shown = new EventEmitter<any>()
secondInstance = new EventEmitter<any>()
constructor(
private logger: Logger
constructor (
private zone: NgZone,
private electron: ElectronService,
log: LogService,
@@ -27,7 +32,7 @@ export class HostAppService {
electron.ipcRenderer.on('host:quit-request', () => this.zone.run(() => this.quitRequested.emit()))
electron.ipcRenderer.on('uncaughtException', function(err) {
electron.ipcRenderer.on('uncaughtException', (err) => {
this.logger.error('Unhandled exception:', err)
})
@@ -44,13 +49,6 @@ export class HostAppService {
})
}
quitRequested = new EventEmitter<any>()
ready = new EventEmitter<any>()
shown = new EventEmitter<any>()
secondInstance = new EventEmitter<any>()
private logger: Logger;
getWindow () {
return this.electron.app.window
}
@@ -63,23 +61,23 @@ export class HostAppService {
return this.electron.app.getAppPath()
}
getPath(type: string) {
getPath (type: string) {
return this.electron.app.getPath(type)
}
openDevTools() {
openDevTools () {
this.getWindow().webContents.openDevTools()
}
setCloseable(flag: boolean) {
setCloseable (flag: boolean) {
this.electron.ipcRenderer.send('window-set-closeable', flag)
}
focusWindow() {
focusWindow () {
this.electron.ipcRenderer.send('window-focus')
}
toggleWindow() {
toggleWindow () {
this.electron.ipcRenderer.send('window-toggle-focus')
}

View File

@@ -4,7 +4,6 @@ import { NativeKeyEvent, stringifyKeySequence } from './hotkeys.util'
import { ConfigService } from '../services/config.service'
import { ElectronService } from '../services/electron.service'
export interface PartialHotkeyMatch {
id: string,
strokes: string[],
@@ -27,7 +26,7 @@ export class HotkeysService {
private disabledLevel = 0
private hotkeyDescriptions: IHotkeyDescription[]
constructor(
constructor (
private zone: NgZone,
private electron: ElectronService,
private config: ConfigService,
@@ -36,7 +35,7 @@ export class HotkeysService {
let events = ['keydown', 'keyup']
events.forEach((event) => {
document.addEventListener(event, (nativeEvent) => {
if (document.querySelectorAll('input:focus').length == 0) {
if (document.querySelectorAll('input:focus').length === 0) {
this.pushKeystroke(event, nativeEvent)
this.processKeystrokes()
this.emitKeyEvent(nativeEvent)
@@ -78,7 +77,7 @@ export class HotkeysService {
this.currentKeystrokes = []
}
getCurrentKeystrokes () : string[] {
getCurrentKeystrokes (): string[] {
this.currentKeystrokes = this.currentKeystrokes.filter((x) => performance.now() - x.time < KEY_TIMEOUT )
return stringifyKeySequence(this.currentKeystrokes.map((x) => x.event))
}
@@ -86,11 +85,11 @@ export class HotkeysService {
registerGlobalHotkey () {
this.electron.globalShortcut.unregisterAll()
let value = this.config.store.hotkeys['toggle-window']
if (typeof value == 'string') {
if (typeof value === 'string') {
value = [value]
}
value.forEach(item => {
item = (typeof item == 'string') ? [item] : item
item = (typeof item === 'string') ? [item] : item
this.electron.globalShortcut.register(item[0].replace(/-/g, '+'), () => {
this.globalHotkey.emit()
@@ -102,16 +101,16 @@ export class HotkeysService {
let keys = {}
for (let key in this.config.store.hotkeys) {
let value = this.config.store.hotkeys[key]
if (typeof value == 'string') {
if (typeof value === 'string') {
value = [value]
}
value = value.map((item) => (typeof item == 'string') ? [item] : item)
value = value.map((item) => (typeof item === 'string') ? [item] : item)
keys[key] = value
}
return keys
}
getCurrentFullyMatchedHotkey () : string {
getCurrentFullyMatchedHotkey (): string {
for (let id in this.getHotkeysConfig()) {
for (let sequence of this.getHotkeysConfig()[id]) {
let currentStrokes = this.getCurrentKeystrokes()
@@ -119,7 +118,7 @@ export class HotkeysService {
break
}
if (sequence.every((x, index) => {
return x.toLowerCase() == currentStrokes[currentStrokes.length - sequence.length + index].toLowerCase()
return x.toLowerCase() === currentStrokes[currentStrokes.length - sequence.length + index].toLowerCase()
})) {
return id
}
@@ -128,16 +127,15 @@ export class HotkeysService {
return null
}
getCurrentPartiallyMatchedHotkeys () : PartialHotkeyMatch[] {
getCurrentPartiallyMatchedHotkeys (): PartialHotkeyMatch[] {
let result = []
for (let id in this.getHotkeysConfig()) {
for (let sequence of this.getHotkeysConfig()[id]) {
let currentStrokes = this.getCurrentKeystrokes()
for (let matchLength = Math.min(currentStrokes.length, sequence.length); matchLength > 0; matchLength--) {
//console.log(sequence, currentStrokes.slice(currentStrokes.length - sequence.length))
if (sequence.slice(0, matchLength).every((x, index) => {
return x.toLowerCase() == currentStrokes[currentStrokes.length - matchLength + index].toLowerCase()
return x.toLowerCase() === currentStrokes[currentStrokes.length - matchLength + index].toLowerCase()
})) {
result.push({
matchedLength: matchLength,
@@ -152,8 +150,8 @@ export class HotkeysService {
return result
}
getHotkeyDescription (id: string) : IHotkeyDescription {
return this.hotkeyDescriptions.filter((x) => x.id == id)[0]
getHotkeyDescription (id: string): IHotkeyDescription {
return this.hotkeyDescriptions.filter((x) => x.id === id)[0]
}
enable () {
@@ -165,12 +163,10 @@ export class HotkeysService {
}
isEnabled () {
return this.disabledLevel == 0
return this.disabledLevel === 0
}
}
@Injectable()
export class AppHotkeyProvider extends HotkeyProvider {
hotkeys: IHotkeyDescription[] = [

View File

@@ -1,18 +1,14 @@
import * as os from 'os'
export const metaKeyName = {
darwin: '⌘',
win32: 'Win',
linux: 'Super',
}[os.platform()]
}[process.platform]
export const altKeyName = {
darwin: 'Option',
win32: 'Alt',
linux: 'Alt',
}[os.platform()]
}[process.platform]
export interface NativeKeyEvent {
event?: string,
@@ -24,14 +20,13 @@ export interface NativeKeyEvent {
keyCode: string,
}
export function stringifyKeySequence(events: NativeKeyEvent[]): string[] {
export function stringifyKeySequence (events: NativeKeyEvent[]): string[] {
let items: string[] = []
events = events.slice()
while (events.length > 0) {
let event = events.shift()
if (event.event == 'keydown') {
if (event.event === 'keydown') {
let itemKeys: string[] = []
if (event.ctrlKey) {
itemKeys.push('Ctrl')
@@ -50,7 +45,7 @@ export function stringifyKeySequence(events: NativeKeyEvent[]): string[] {
// TODO make this optional?
continue
}
if (event.key.length == 1) {
if (event.key.length === 1) {
itemKeys.push(event.key.toUpperCase())
} else {
itemKeys.push(event.key)

View File

@@ -1,8 +1,7 @@
import { Injectable } from '@angular/core'
export class Logger {
constructor(
constructor (
private name: string,
) {}
@@ -10,10 +9,10 @@ export class Logger {
console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
}
debug(...args: any[]) { this.log('debug', ...args) }
info(...args: any[]) { this.log('info', ...args) }
warn(...args: any[]) { this.log('warn', ...args) }
error(...args: any[]) { this.log('error', ...args) }
debug (...args: any[]) { this.log('debug', ...args) }
info (...args: any[]) { this.log('info', ...args) }
warn (...args: any[]) { this.log('warn', ...args) }
error (...args: any[]) { this.log('error', ...args) }
}
@Injectable()

View File

@@ -1,18 +1,17 @@
import { Injectable } from '@angular/core'
import { ToasterService } from 'angular2-toaster'
@Injectable()
export class NotifyService {
constructor(
constructor (
private toaster: ToasterService,
) {}
pop(options) {
pop (options) {
this.toaster.pop(options)
}
info(title: string, body: string = null) {
info (title: string, body: string = null) {
return this.pop({
type: 'info',
title, body,
@@ -20,7 +19,7 @@ export class NotifyService {
})
}
success(title: string, body: string = null) {
success (title: string, body: string = null) {
return this.pop({
type: 'success',
title, body,
@@ -28,7 +27,7 @@ export class NotifyService {
})
}
warning(title: string, body: string = null) {
warning (title: string, body: string = null) {
return this.pop({
type: 'warning',
title, body,
@@ -36,7 +35,7 @@ export class NotifyService {
})
}
error(title: string, body: string = null) {
error (title: string, body: string = null) {
return this.pop({
type: 'error',
title, body,

View File

@@ -1,21 +0,0 @@
import { Injectable } from '@angular/core'
class Plugin {
ngModule: any
name: string
}
@Injectable()
export class PluginsService {
plugins: Plugin[] = []
register (plugin: Plugin): void {
this.plugins.push(plugin)
}
getModules (): any[] {
return this.plugins.map((plugin) => plugin.ngModule)
}
}

View File

@@ -1,10 +1,9 @@
import { Injectable } from '@angular/core'
import { HostAppService } from '../services/hostApp.service'
@Injectable()
export class QuitterService {
constructor(
constructor (
private hostApp: HostAppService,
) {
hostApp.quitRequested.subscribe(() => {
@@ -12,7 +11,7 @@ export class QuitterService {
})
}
quit() {
quit () {
this.hostApp.setCloseable(true)
this.hostApp.quit()
}

View File

@@ -4,12 +4,11 @@ import { BaseTabComponent } from '../components/baseTab.component'
import { Logger, LogService } from '../services/log.service'
import { AppService } from '../services/app.service'
@Injectable()
export class TabRecoveryService {
logger: Logger
constructor(
constructor (
@Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[],
app: AppService,
log: LogService

View File

@@ -2,7 +2,6 @@ import { Inject, Injectable } from '@angular/core'
import { ConfigService } from '../services/config.service'
import { Theme } from '../api/theme'
@Injectable()
export class ThemesService {
private styleElement: HTMLElement = null

View File

@@ -1,7 +1,6 @@
import { Injectable } from '@angular/core'
import { Theme } from './api'
@Injectable()
export class StandardTheme extends Theme {
name = 'Standard'