2021-10-30 17:26:41 +00:00
|
|
|
import * as electronRemote from '@electron/remote';
|
|
|
|
const electronConsole = electronRemote.getGlobal('console') as Console;
|
|
|
|
import Logger from '../../../logger/logger';
|
2021-11-02 04:29:24 +00:00
|
|
|
const LOG = Logger.create(__filename, electronConsole);
|
2021-10-30 17:26:41 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
}
|