cordis/client/webapp/elements/events-text-input.ts

147 lines
5.1 KiB
TypeScript

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 ElementsUtil from './require/elements-util.js';
import Globals from '../globals';
import { Channel } from '../data-types';
import Q from '../q-module';
import UI from '../ui';
import createUploadOverlayFromPath from './overlay-upload-path';
import createUploadOverlayFromDataTransferItem from './overlay-upload-datatransfer';
import createUploadDropTarget from './overlay-upload-drop-target';
import CombinedGuild from '../guild-combined';
export default function bindTextInputEvents(document: Document, q: Q, ui: UI): void {
// Send Current Channel Messages
let sendingMessage = false;
async function sendCurrentTextMessage() {
if (sendingMessage) return;
if (ui.activeGuild === null) return;
if (ui.activeChannel === null) return;
let text = q.$('#text-input').innerText.trim(); // trimming is not done server-side, just a client-side 'feature'
if (text == '') return;
sendingMessage = true;
let guild = ui.activeGuild as CombinedGuild;
let channel = ui.activeChannel as Channel;
if (!guild.isSocketVerified()) {
LOG.warn('client attempted to send message while not verified');
q.$('#send-error').innerText = 'Not Connected to Server';
await ElementsUtil.shakeElement(q.$('#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');
q.$('#send-error').innerText = 'Message too long: ' + text.length + ' > ' + Globals.MAX_TEXT_MESSAGE_LENGTH + ' characters';
await ElementsUtil.shakeElement(q.$('#send-error'), 400);
sendingMessage = false;
return;
}
await ui.lockMessages(guild, channel, async () => {
q.$('#text-input').removeAttribute('contenteditable');
q.$('#text-input').classList.add('sending');
try {
await guild.requestSendMessage(channel.id, text);
q.$('#send-error').innerText = '';
q.$('#text-input').innerText = '';
} catch (e) {
LOG.error('Error sending message', e);
q.$('#send-error').innerText = 'Error sending message';
await ElementsUtil.shakeElement(q.$('#send-error'), 400);
}
q.$('#text-input').classList.remove('sending');
q.$('#text-input').setAttribute('contenteditable', 'plaintext-only');
q.$('#text-input').focus();
});
sendingMessage = false;
};
q.$('#text-input').addEventListener('keydown', async (e) => {
if (!sendingMessage) {
q.$('#send-error').innerText = ''; // clear out the sending error if the message changes
}
if (e.key == 'Enter' && !e.shiftKey) {
e.preventDefault();
await sendCurrentTextMessage();
}
});
q.$('#text-input').addEventListener('keyup', (e) => {
if (e.key == 'Backspace') {
if (q.$('#text-input').innerText == '\n') { // sometimes, a \n gets left behind
q.$('#text-input').innerText = '';
}
}
});
q.$('#send-error').addEventListener('click', () => {
q.$('#send-error').innerText = '';
});
// Open resource select dialog when resource-input-button is clicked
let selectingResources = false;
q.$('#resource-input-button').addEventListener('click', async () => {
if (ui.activeGuild === null) return;
if (ui.activeChannel === null) 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 = createUploadOverlayFromPath(document, ui.activeGuild, ui.activeChannel, result.filePaths[0]);
document.body.appendChild(element);
q.$$$(element, '.text-input').focus();
}
selectingResources = false;
});
// Open upload resource dialog when an image is pasted
window.addEventListener('paste', (e) => {
if (ui.activeGuild === null) return;
if (ui.activeChannel === null) 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 = createUploadOverlayFromDataTransferItem(document, ui.activeGuild, ui.activeChannel, fileTransferItem);
document.body.appendChild(element);
q.$$$(element, '.text-input').focus();
}
});
// TODO: drag+drop new server files?
document.addEventListener('dragenter', () => {
if (ui.activeGuild === null) return;
if (ui.activeChannel === null) return;
if (q.$('.overlay .drop-target')) return;
let element = createUploadDropTarget(document, q, ui.activeGuild, ui.activeChannel);
if (!element) return;
document.body.appendChild(element);
});
}