import * as electronRemote from '@electron/remote'; const electronConsole = electronRemote.getGlobal('console') as Console; import Logger from '../../../logger/logger'; const LOG = Logger.create(__filename, electronConsole); import Elements from '../elements'; import ElementsUtil from './require/elements-util.js'; import Globals from '../globals'; import { $, $$, $$$, $$$$ } from './require/q-module'; import IState from './require/elements-state'; import { Channel } from '../data-types'; import ClientController from '../client-controller'; export default function bindTextInputEvents(state: IState): void { const { document, ui } = state; $.setDocument(document); // Send Current Channel Messages let sendingMessage = false; async function sendCurrentTextMessage() { if (sendingMessage) return; if (!ui.hasActiveServer()) return; if (!ui.hasActiveChannel()) return; let text = $('#text-input').innerText.trim(); // trimming is not done server-side, just a client-side 'feature' if (text == '') return; sendingMessage = true; let server = ui.activeServer as ClientController; let channel = ui.activeChannel as Channel; if (!server.isVerified) { LOG.warn('client attempted to send message while not verified'); $('#send-error').innerText = 'Not Connected to Server'; await ElementsUtil.shakeElement($('#send-error'), 400); sendingMessage = false; return; } if (text.length > Globals.MAX_TEXT_MESSAGE_LENGTH) { LOG.warn('skipping sending oversized message: ' + text.length + ' > ' + Globals.MAX_TEXT_MESSAGE_LENGTH + ' characters'); $('#send-error').innerText = 'Message too long: ' + text.length + ' > ' + Globals.MAX_TEXT_MESSAGE_LENGTH + ' characters'; await ElementsUtil.shakeElement($('#send-error'), 400); sendingMessage = false; return; } await ui.lockMessages(server, channel, async () => { $('#text-input').removeAttribute('contenteditable'); $('#text-input').classList.add('sending'); try { await server.sendMessage(channel.id, text); $('#send-error').innerText = ''; $('#text-input').innerText = ''; } catch (e) { LOG.error('Error sending message', e); $('#send-error').innerText = 'Error sending message'; await ElementsUtil.shakeElement($('#send-error'), 400); } $('#text-input').classList.remove('sending'); $('#text-input').setAttribute('contenteditable', 'plaintext-only'); $('#text-input').focus(); }); sendingMessage = false; }; $('#text-input').addEventListener('keydown', async (e) => { if (!sendingMessage) { $('#send-error').innerText = ''; // clear out the sending error if the message changes } if (e.key == 'Enter' && !e.shiftKey) { e.preventDefault(); await sendCurrentTextMessage(); } }); $('#text-input').addEventListener('keyup', (e) => { if (e.key == 'Backspace') { if ($('#text-input').innerText == '\n') { // sometimes, a \n gets left behind $('#text-input').innerText = ''; } } }); $('#send-error').addEventListener('click', () => { $('#send-error').innerText = ''; }); // Open resource select dialog when resource-input-button is clicked let selectingResources = false; $('#resource-input-button').addEventListener('click', async () => { if (!ui.hasActiveServer()) return; if (!ui.hasActiveChannel()) return; if (selectingResources) { return; } selectingResources = true; let result = await electronRemote.dialog.showOpenDialog({ title: 'Select Resource', defaultPath: 'D:\\development\\cordis\\client-server\\server\\data', // TODO: not hardcoded properties: [ 'openFile' ] }); // TODO: multiple files do consecutive overlays? if (!result.canceled) { let element = Elements.createUploadOverlayFromPath(ui.activeServer as ClientController, ui.activeChannel as Channel, result.filePaths[0]); document.body.appendChild(element); $$$(element, '.text-input').focus(); } selectingResources = false; }); // Open upload resource dialog when an image is pasted window.addEventListener('paste', (e) => { if (!ui.hasActiveServer()) return; if (!ui.hasActiveChannel()) return; let fileTransferItem: DataTransferItem | null = null; for (let item of (e as ClipboardEvent).clipboardData?.items ?? []) { if (item.kind == 'file') { e.preventDefault(); // don't continue the paste fileTransferItem = item; break; } } if (fileTransferItem) { let element = Elements.createUploadOverlayFromDataTransferItem(ui.activeServer as ClientController, ui.activeChannel as Channel, fileTransferItem); document.body.appendChild(element); $$$(element, '.text-input').focus(); } }); // TODO: drag+drop new server files? document.addEventListener('dragenter', () => { if ($('.overlay .drop-target')) return; let element = Elements.createUploadDropTarget(ui.activeServer as ClientController, ui.activeChannel as Channel); if (!element) return; document.body.appendChild(element); }); }