window["require_setup"](module); import * as electron from "electron"; const remote = electron.remote; const {Menu, MenuItem} = remote; import {isFunction} from "util"; import NativeImage = electron.NativeImage; class ElectronContextMenu implements contextmenu.ContextMenuProvider { private _close_listeners: (() => any)[] = []; private _current_menu: electron.Menu; private _icon_mash_url: string; private _icon_mask_img: NativeImage; private _div: JQuery; despawn_context_menu() { if(!this._current_menu) return; this._current_menu.closePopup(); this._current_menu = undefined; for(const listener of this._close_listeners) listener(); this._close_listeners = []; } finalize() { this._icon_mask_img = undefined; this._icon_mash_url = undefined; if(this._div) this._div.detach(); this._div = undefined; this._cache_klass_map = undefined; } initialize() { this.initialize_icons(); } private async initialize_icons() { if(!this._div) { this._div = $.spawn("div"); this._div.css('display', 'none'); this._div.appendTo(document.body); } const image = new Image(); image.src = 'img/client_icon_sprite.svg'; await new Promise((resolve, reject) => { image.onload = resolve; image.onerror = reject; }); /* TODO: Get a size! */ const canvas = document.createElement("canvas"); canvas.width = 1024; canvas.height = 1024; canvas.getContext("2d").drawImage(image, 0, 0); this._icon_mash_url = canvas.toDataURL(); this._icon_mask_img = remote.nativeImage.createFromDataURL(this._icon_mash_url); } private _cache_klass_map: {[key: string]: NativeImage} = {}; private class_to_image(klass: string) : NativeImage { if(!klass || !this._icon_mask_img) return undefined; if(this._cache_klass_map[klass]) return this._cache_klass_map[klass]; this._div[0].classList.value = 'icon ' + klass; const data = window.getComputedStyle(this._div[0]); const offset_x = parseInt(data.backgroundPositionX.split(",")[0]); const offset_y = parseInt(data.backgroundPositionY.split(",")[0]); //http://localhost/home/TeaSpeak/Web-Client/web/environment/development/img/client_icon_sprite.svg //const hight = element.css('height'); //const width = element.css('width'); console.log("Offset: x: %o y: %o;", offset_x, offset_y); return this._cache_klass_map[klass] = this._icon_mask_img.crop({ height: 16, width: 16, x: offset_x == 0 ? 0 : -offset_x, y: offset_y == 0 ? 0 : -offset_y }); } private _entry_id = 0; private build_menu(entry: contextmenu.MenuEntry) : electron.MenuItem { if(entry.type == contextmenu.MenuEntryType.CLOSE) { this._close_listeners.push(entry.callback); return undefined; } const click_callback = () => { if(entry.callback) entry.callback(); this.despawn_context_menu(); }; const _id = "entry_" + (this._entry_id++); if(entry.type == contextmenu.MenuEntryType.ENTRY) { return new MenuItem({ id: _id, label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string, type: "normal", click: click_callback, icon: this.class_to_image(entry.icon_class), visible: entry.visible, enabled: !entry.disabled }); } else if(entry.type == contextmenu.MenuEntryType.HR) { if(typeof(entry.visible) === "boolean" && !entry.visible) return undefined; return new MenuItem({ id: _id, type: "separator", label: '', click: click_callback }) } else if(entry.type == contextmenu.MenuEntryType.CHECKBOX) { return new MenuItem({ id: _id, label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string, type: "checkbox", checked: !!entry.checkbox_checked, click: click_callback, icon: this.class_to_image(entry.icon_class), visible: entry.visible, enabled: !entry.disabled }); } else if (entry.type == contextmenu.MenuEntryType.SUB_MENU) { const sub_menu = new Menu(); for(const e of entry.sub_menu) { const build = this.build_menu(e); if(!build) continue; sub_menu.append(build); } return new MenuItem({ id: _id, label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string, type: "submenu", submenu: sub_menu, click: click_callback, icon: this.class_to_image(entry.icon_class), visible: entry.visible, enabled: !entry.disabled }); } return undefined; } spawn_context_menu(x: number, y: number, ...entries: contextmenu.MenuEntry[]) { this.despawn_context_menu(); this._current_menu = new Menu(); for(const entry of entries) { const build = this.build_menu(entry); if(!build) continue; this._current_menu.append(build); } this._current_menu.popup({ window: remote.getCurrentWindow(), x: x, y: y, callback: () => this.despawn_context_menu() }); } html_format_enabled() { return false; } } contextmenu.set_provider(new ElectronContextMenu()); export {};