mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-18 10:30:01 +00:00
179 lines
6.7 KiB
TypeScript
179 lines
6.7 KiB
TypeScript
import { Component, Input, HostBinding, HostListener, NgZone, ViewChild, ElementRef } from '@angular/core'
|
|
import { SortableComponent } from 'ng2-dnd'
|
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
|
import { BaseTabComponent } from './baseTab.component'
|
|
import { RenameTabModalComponent } from './renameTabModal.component'
|
|
import { HotkeysService } from '../services/hotkeys.service'
|
|
import { ElectronService } from '../services/electron.service'
|
|
import { AppService } from '../services/app.service'
|
|
import { HostAppService, Platform } from '../services/hostApp.service'
|
|
|
|
const COLORS = [
|
|
{ name: 'No color', value: null },
|
|
{ name: 'Blue', value: '#0275d8' },
|
|
{ name: 'Green', value: '#5cb85c' },
|
|
{ name: 'Orange', value: '#f0ad4e' },
|
|
{ name: 'Purple', value: '#613d7c' },
|
|
{ name: 'Red', value: '#d9534f' },
|
|
{ name: 'Yellow', value: '#ffd500' },
|
|
]
|
|
|
|
@Component({
|
|
selector: 'tab-header',
|
|
template: require('./tabHeader.component.pug'),
|
|
styles: [require('./tabHeader.component.scss')],
|
|
})
|
|
export class TabHeaderComponent {
|
|
@Input() index: number
|
|
@Input() @HostBinding('class.active') active: boolean
|
|
@Input() @HostBinding('class.has-activity') hasActivity: boolean
|
|
@Input() tab: BaseTabComponent
|
|
@Input() progress: number
|
|
@ViewChild('handle') handle: ElementRef
|
|
|
|
private completionNotificationEnabled = false
|
|
|
|
constructor (
|
|
public app: AppService,
|
|
private electron: ElectronService,
|
|
private zone: NgZone,
|
|
private hostApp: HostAppService,
|
|
private ngbModal: NgbModal,
|
|
private hotkeys: HotkeysService,
|
|
private parentDraggable: SortableComponent,
|
|
) {
|
|
this.hotkeys.matchedHotkey.subscribe((hotkey) => {
|
|
if (this.app.activeTab === this.tab) {
|
|
if (hotkey === 'rename-tab') {
|
|
this.showRenameTabModal()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
ngOnInit () {
|
|
if (this.hostApp.platform === Platform.macOS) {
|
|
this.parentDraggable.setDragHandle(this.handle.nativeElement)
|
|
}
|
|
this.tab.progress$.subscribe(progress => {
|
|
this.progress = progress
|
|
})
|
|
}
|
|
|
|
showRenameTabModal (): void {
|
|
let modal = this.ngbModal.open(RenameTabModalComponent)
|
|
modal.componentInstance.value = this.tab.customTitle || this.tab.title
|
|
setTimeout(() => {
|
|
const inputElement = modal.componentInstance.input.nativeElement as HTMLInputElement
|
|
inputElement.select()
|
|
}, 250)
|
|
modal.result.then(result => {
|
|
this.tab.setTitle(result)
|
|
this.tab.customTitle = result
|
|
}).catch(() => null)
|
|
}
|
|
|
|
@HostListener('dblclick') onDoubleClick (): void {
|
|
this.showRenameTabModal()
|
|
}
|
|
|
|
@HostListener('auxclick', ['$event']) async onAuxClick ($event: MouseEvent) {
|
|
if ($event.which === 2) {
|
|
this.app.closeTab(this.tab, true)
|
|
}
|
|
if ($event.which === 3) {
|
|
event.preventDefault()
|
|
|
|
let contextMenu = this.electron.remote.Menu.buildFromTemplate([
|
|
{
|
|
label: 'Close',
|
|
click: () => this.zone.run(() => {
|
|
this.app.closeTab(this.tab, true)
|
|
})
|
|
},
|
|
{
|
|
label: 'Close other tabs',
|
|
click: () => this.zone.run(() => {
|
|
for (let tab of this.app.tabs.filter(x => x !== this.tab)) {
|
|
this.app.closeTab(tab, true)
|
|
}
|
|
})
|
|
},
|
|
{
|
|
label: 'Close tabs to the right',
|
|
click: () => this.zone.run(() => {
|
|
for (let tab of this.app.tabs.slice(this.app.tabs.indexOf(this.tab) + 1)) {
|
|
this.app.closeTab(tab, true)
|
|
}
|
|
})
|
|
},
|
|
{
|
|
label: 'Close tabs to the left',
|
|
click: () => this.zone.run(() => {
|
|
for (let tab of this.app.tabs.slice(0, this.app.tabs.indexOf(this.tab))) {
|
|
this.app.closeTab(tab, true)
|
|
}
|
|
})
|
|
},
|
|
{
|
|
label: 'Rename',
|
|
click: () => this.zone.run( () => this.showRenameTabModal() )
|
|
},
|
|
{
|
|
label: 'Color',
|
|
sublabel: COLORS.find(x => x.value === this.tab.color).name,
|
|
submenu: COLORS.map(color => ({
|
|
label: color.name,
|
|
type: 'radio',
|
|
checked: this.tab.color === color.value,
|
|
click: () => this.zone.run(() => {
|
|
this.tab.color = color.value
|
|
}),
|
|
})),
|
|
}
|
|
])
|
|
|
|
let process = await this.tab.getCurrentProcess()
|
|
if (process) {
|
|
contextMenu.append(new this.electron.MenuItem({
|
|
id: 'sep',
|
|
type: 'separator',
|
|
}))
|
|
contextMenu.append(new this.electron.MenuItem({
|
|
id: 'process-name',
|
|
enabled: false,
|
|
label: 'Current process: ' + process.name,
|
|
}))
|
|
contextMenu.append(new this.electron.MenuItem({
|
|
id: 'completion',
|
|
label: 'Notify when done',
|
|
type: 'checkbox',
|
|
checked: this.completionNotificationEnabled,
|
|
click: () => this.zone.run(() => {
|
|
this.completionNotificationEnabled = !this.completionNotificationEnabled
|
|
|
|
if (this.completionNotificationEnabled) {
|
|
this.app.observeTabCompletion(this.tab).subscribe(() => {
|
|
new Notification('Process completed', {
|
|
body: process.name,
|
|
}).addEventListener('click', () => {
|
|
this.app.selectTab(this.tab)
|
|
})
|
|
this.completionNotificationEnabled = false
|
|
})
|
|
} else {
|
|
this.app.stopObservingTabCompletion(this.tab)
|
|
}
|
|
})
|
|
}))
|
|
}
|
|
|
|
contextMenu.popup({
|
|
x: $event.pageX,
|
|
y: $event.pageY,
|
|
async: true,
|
|
})
|
|
}
|
|
}
|
|
}
|