2021-06-29 21:57:04 +00:00
|
|
|
import '@vaadin/vaadin-context-menu'
|
2021-05-24 15:48:12 +00:00
|
|
|
import copyToClipboard from 'copy-text-to-clipboard'
|
2021-06-27 17:08:37 +00:00
|
|
|
import { Injectable, Inject } from '@angular/core'
|
2021-06-03 17:07:48 +00:00
|
|
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
2021-06-29 21:57:04 +00:00
|
|
|
import { PlatformService, ClipboardContent, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileUploadOptions, FileDownload, HTMLFileUpload } from 'tabby-core'
|
2021-05-24 15:48:12 +00:00
|
|
|
|
|
|
|
// eslint-disable-next-line no-duplicate-imports
|
2021-06-29 21:57:04 +00:00
|
|
|
import type { ContextMenuElement, ContextMenuItem } from '@vaadin/vaadin-context-menu'
|
2021-05-24 15:48:12 +00:00
|
|
|
|
2021-06-03 17:07:48 +00:00
|
|
|
import { MessageBoxModalComponent } from './components/messageBoxModal.component'
|
2021-05-24 15:48:12 +00:00
|
|
|
import './styles.scss'
|
|
|
|
|
2021-06-15 21:43:02 +00:00
|
|
|
|
2021-05-24 15:48:12 +00:00
|
|
|
@Injectable()
|
|
|
|
export class WebPlatformService extends PlatformService {
|
|
|
|
private menu: ContextMenuElement
|
|
|
|
private contextMenuHandlers = new Map<ContextMenuItem, () => void>()
|
2021-06-12 11:05:09 +00:00
|
|
|
private fileSelector: HTMLInputElement
|
2021-05-24 15:48:12 +00:00
|
|
|
|
2021-06-03 17:07:48 +00:00
|
|
|
constructor (
|
2021-06-27 17:08:37 +00:00
|
|
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
|
|
@Inject('WEB_CONNECTOR') private connector: any,
|
2021-06-03 17:07:48 +00:00
|
|
|
private ngbModal: NgbModal,
|
|
|
|
) {
|
2021-05-24 15:48:12 +00:00
|
|
|
super()
|
|
|
|
this.menu = window.document.createElement('vaadin-context-menu')
|
|
|
|
this.menu.addEventListener('item-selected', e => {
|
|
|
|
this.contextMenuHandlers.get(e.detail.value)?.()
|
|
|
|
})
|
|
|
|
document.body.appendChild(this.menu)
|
2021-06-12 11:05:09 +00:00
|
|
|
|
|
|
|
this.fileSelector = document.createElement('input')
|
|
|
|
this.fileSelector.type = 'file'
|
|
|
|
this.fileSelector.style.visibility = 'hidden'
|
|
|
|
document.body.appendChild(this.fileSelector)
|
2021-06-03 17:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
readClipboard (): string {
|
|
|
|
return ''
|
2021-05-24 15:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
setClipboard (content: ClipboardContent): void {
|
|
|
|
copyToClipboard(content.text)
|
|
|
|
}
|
|
|
|
|
|
|
|
async loadConfig (): Promise<string> {
|
2021-06-15 21:43:02 +00:00
|
|
|
return this.connector.loadConfig()
|
2021-05-24 15:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async saveConfig (content: string): Promise<void> {
|
2021-06-15 21:43:02 +00:00
|
|
|
await this.connector.saveConfig(content)
|
2021-05-24 15:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
getOSRelease (): string {
|
|
|
|
return '1.0'
|
|
|
|
}
|
|
|
|
|
|
|
|
openExternal (url: string): void {
|
|
|
|
window.open(url)
|
|
|
|
}
|
|
|
|
|
|
|
|
getAppVersion (): string {
|
2021-06-18 23:36:25 +00:00
|
|
|
return this.connector.getAppVersion()
|
2021-05-24 15:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async listFonts (): Promise<string[]> {
|
|
|
|
return []
|
|
|
|
}
|
|
|
|
|
|
|
|
popupContextMenu (menu: MenuItemOptions[], event?: MouseEvent): void {
|
|
|
|
this.contextMenuHandlers.clear()
|
|
|
|
this.menu.items = menu
|
|
|
|
.filter(x => x.type !== 'separator')
|
|
|
|
.map(x => this.remapMenuItem(x))
|
|
|
|
setTimeout(() => {
|
|
|
|
this.menu.open(event)
|
|
|
|
}, 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
private remapMenuItem (item: MenuItemOptions): ContextMenuItem {
|
|
|
|
const cmi = {
|
|
|
|
text: item.label,
|
|
|
|
disabled: !(item.enabled ?? true),
|
|
|
|
checked: item.checked,
|
|
|
|
children: item.submenu?.map(i => this.remapMenuItem(i)),
|
|
|
|
}
|
|
|
|
if (item.click) {
|
|
|
|
this.contextMenuHandlers.set(cmi, item.click)
|
|
|
|
}
|
|
|
|
return cmi
|
|
|
|
}
|
2021-06-03 17:07:48 +00:00
|
|
|
|
|
|
|
async showMessageBox (options: MessageBoxOptions): Promise<MessageBoxResult> {
|
|
|
|
const modal = this.ngbModal.open(MessageBoxModalComponent, {
|
|
|
|
backdrop: 'static',
|
|
|
|
})
|
|
|
|
const instance: MessageBoxModalComponent = modal.componentInstance
|
|
|
|
instance.options = options
|
|
|
|
try {
|
|
|
|
const response = await modal.result
|
|
|
|
return { response }
|
|
|
|
} catch {
|
|
|
|
return { response: 0 }
|
|
|
|
}
|
|
|
|
}
|
2021-06-05 17:13:22 +00:00
|
|
|
|
|
|
|
quit (): void {
|
|
|
|
window.close()
|
|
|
|
}
|
2021-06-12 11:05:09 +00:00
|
|
|
|
|
|
|
async startDownload (name: string, size: number): Promise<FileDownload|null> {
|
|
|
|
const transfer = new HTMLFileDownload(name, size)
|
|
|
|
this.fileTransferStarted.next(transfer)
|
|
|
|
return transfer
|
|
|
|
}
|
|
|
|
|
|
|
|
startUpload (options?: FileUploadOptions): Promise<FileUpload[]> {
|
|
|
|
return new Promise(resolve => {
|
|
|
|
this.fileSelector.onchange = () => {
|
|
|
|
const transfers: FileUpload[] = []
|
|
|
|
const fileList = this.fileSelector.files!
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
|
|
for (let i = 0; i < (fileList.length ?? 0); i++) {
|
|
|
|
const file = fileList[i]
|
|
|
|
const transfer = new HTMLFileUpload(file)
|
|
|
|
this.fileTransferStarted.next(transfer)
|
|
|
|
transfers.push(transfer)
|
|
|
|
if (!options?.multiple) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
resolve(transfers)
|
|
|
|
}
|
|
|
|
this.fileSelector.click()
|
|
|
|
})
|
|
|
|
}
|
2021-06-18 23:36:25 +00:00
|
|
|
|
|
|
|
setErrorHandler (handler: (_: any) => void): void {
|
|
|
|
window.addEventListener('error', handler)
|
|
|
|
}
|
2021-06-12 11:05:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class HTMLFileDownload extends FileDownload {
|
|
|
|
private buffers: Buffer[] = []
|
|
|
|
|
|
|
|
constructor (
|
|
|
|
private name: string,
|
|
|
|
private size: number,
|
|
|
|
) {
|
|
|
|
super()
|
|
|
|
}
|
|
|
|
|
|
|
|
getName (): string {
|
|
|
|
return this.name
|
|
|
|
}
|
|
|
|
|
|
|
|
getSize (): number {
|
|
|
|
return this.size
|
|
|
|
}
|
|
|
|
|
|
|
|
async write (buffer: Buffer): Promise<void> {
|
|
|
|
this.buffers.push(Buffer.from(buffer))
|
|
|
|
this.increaseProgress(buffer.length)
|
|
|
|
if (this.isComplete()) {
|
|
|
|
this.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
finish () {
|
|
|
|
const blob = new Blob(this.buffers, { type: 'application/octet-stream' })
|
|
|
|
const element = window.document.createElement('a')
|
|
|
|
element.href = window.URL.createObjectURL(blob)
|
|
|
|
element.download = this.name
|
|
|
|
document.body.appendChild(element)
|
|
|
|
element.click()
|
|
|
|
document.body.removeChild(element)
|
|
|
|
}
|
|
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
|
|
close (): void { }
|
2021-05-24 15:48:12 +00:00
|
|
|
}
|