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 ClientController from "../client-controller"; import Globals from "../globals"; import BaseElements from "./require/base-elements"; import IState from "./require/elements-state"; import ElementsUtil from "./require/elements-util"; import { $, $$, $$$, $$$$ } from './require/q-module'; export default function createCreateChannelOverlay(state: IState, server: ClientController): HTMLElement { const { document, ui } = state; $.setDocument(document); // See also overlay-modify-channel let element = BaseElements.createOverlay(document, { class: 'content submit-dialog modify-channel', content: [ { class: 'preview channel-title', content: [ { class: 'channel-icon', content: BaseElements.TEXT_CHANNEL_ICON }, { class: 'channel-name', content: 'channel-name' }, { class: 'channel-flavor-divider' }, { class: 'channel-flavor-text', content: '' } ] }, { class: 'text-input channel-name', placeholder: 'channel-name', content: '', contenteditable: 'plaintext-only' }, { class: 'text-input channel-flavor-text', placeholder: 'Flavor Text (optional)', content: '' || '', contenteditable: 'plaintext-only' }, { class: 'lower', content: [ { class: 'error' }, { class: 'buttons', content: [ { class: 'button submit', content: 'Create Channel' } ] } ] } ] }); let newName = ''; let newFlavorText: string | null = ''; function updatePreview() { newName = $$$(element, '.text-input.channel-name').innerText; newFlavorText = $$$(element, '.text-input.channel-flavor-text').innerText; $$$(element, '.channel-title .channel-name').innerText = newName; $$$(element, '.channel-title .channel-flavor-text').innerText = newFlavorText; if (newFlavorText != '') { $$$(element, '.channel-title .channel-flavor-divider').style.visibility = 'visible'; } else { $$$(element, '.channel-title .channel-flavor-divider').style.visibility = 'hidden'; } } updatePreview(); let submitting = false; async function submit() { if (submitting) return; submitting = true; $$$(element, '.error').innerText = ''; $$$(element, '.button.submit').innerText = 'Submitting...'; $$$(element, '.text-input.channel-name').removeAttribute('contenteditable'); $$$(element, '.text-input.channel-flavor-text').removeAttribute('contenteditable'); let success = false; if (newName.length == 0) { LOG.warn('attempted to set empty channel name'); $$$(element, '.error').innerText = 'Channel name cannot be empty'; $$$(element, '.button.submit').innerText = 'Try Again'; await ElementsUtil.shakeElement($$$(element, '.button.submit'), 400); } else if (newName.length > Globals.MAX_CHANNEL_NAME_LENGTH) { LOG.warn('attempted to set too long channel name'); $$$(element, '.error').innerText = 'Channel name is too long. ' + newName.length + ' > ' + Globals.MAX_CHANNEL_NAME_LENGTH; $$$(element, '.button.submit').innerText = 'Try Again'; await ElementsUtil.shakeElement($$$(element, '.button.submit'), 400); } else if (!(/^[A-Za-z0-9-]+$/.exec(newName))) { LOG.warn('attempted to set channel name with illegal characters'); $$$(element, '.error').innerText = 'Please use only [A-Za-z0-9-]+ in channel name'; $$$(element, '.button.submit').innerText = 'Try Again'; await ElementsUtil.shakeElement($$$(element, '.button.submit'), 400); } else if (newFlavorText != null && newFlavorText.length > Globals.MAX_CHANNEL_FLAVOR_TEXT_LENGTH) { LOG.warn('attempted to set too long flavor text'); $$$(element, '.error').innerText = 'Flavor text is too long. ' + newName.length + ' > ' + Globals.MAX_CHANNEL_NAME_LENGTH; $$$(element, '.button.submit').innerText = 'Try Again'; await ElementsUtil.shakeElement($$$(element, '.button.submit'), 400); } else { if (newFlavorText != null && newFlavorText.length == 0) { newFlavorText = null; } try { await server.createChannel(newName, newFlavorText); success = true; } catch (e) { LOG.error('error updating channel', e); $$$(element, '.error').innerText = 'Error updating channel'; $$$(element, '.button.submit').innerText = 'Try Again'; await ElementsUtil.shakeElement($$$(element, '.button.submit'), 400); } } if (success) { element.removeSelf(); } $$$(element, '.text-input.channel-name').setAttribute('contenteditable', 'plaintext-only'); $$$(element, '.text-input.channel-flavor-text').setAttribute('contenteditable', 'plaintext-only'); submitting = false; } let textInputs = $$$$(element, '.text-input'); for (let textInput of textInputs) { textInput.addEventListener('input', () => { updatePreview(); }); } $$$(element, '.text-input.channel-name').addEventListener('keydown', async (e) => { if (e.key == 'Backspace' || e.key == 'Escape' || e.key == 'F4') { // these keys are good } else if (e.key == 'Tab') { // have to hard-code this one because otherwise, it just picks the beginning of the next input e.preventDefault(); e.stopPropagation(); $$$(element, '.text-input.channel-flavor-text').focus(); ElementsUtil.setCursorToEnd($$$(element, '.text-input.channel-flavor-text')); } else if (e.key == 'Enter') { e.preventDefault(); e.stopPropagation(); await submit(); } else if (!/^[A-Za-z0-9-]$/.exec(e.key)) { e.preventDefault(); e.stopPropagation(); } }); $$$(element, '.text-input.channel-flavor-text').addEventListener('keydown', async (e) => { if (e.key == 'Tab' && e.shiftKey) { // have to hard-code this one because otherwise, it just picks the beginning of the next input e.preventDefault(); e.stopPropagation(); $$$(element, '.text-input.channel-name').focus(); ElementsUtil.setCursorToEnd($$$(element, '.text-input.channel-name')); } else if (e.key == 'Enter') { e.preventDefault(); e.stopPropagation(); await submit(); } }); $$$(element, '.button.submit').addEventListener('click', async () => { await submit(); }); return element; } module.exports = createCreateChannelOverlay;