From b549b21257f6ade152471cd255264aadaa30b024 Mon Sep 17 00:00:00 2001 From: Ginger Wong Date: Wed, 26 Aug 2020 11:56:01 -0700 Subject: [PATCH] add utils to help cleanup whitespaces from contenteditable output; removed forced chat enabling --- webroot/js/app.js | 2 +- webroot/js/components/chat/chat-input.js | 7 +- webroot/js/utils/chat.js | 94 +++++++++++++++++++++++- 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/webroot/js/app.js b/webroot/js/app.js index 29e355f28..2f20f374f 100644 --- a/webroot/js/app.js +++ b/webroot/js/app.js @@ -470,7 +470,7 @@ export default class App extends Component { websocket=${websocket} username=${username} userAvatarImage=${userAvatarImage} - chatEnabled //=${chatEnabled} + chatEnabled=${chatEnabled} /> ` diff --git a/webroot/js/components/chat/chat-input.js b/webroot/js/components/chat/chat-input.js index 99bbe83bd..219be9d96 100644 --- a/webroot/js/components/chat/chat-input.js +++ b/webroot/js/components/chat/chat-input.js @@ -4,7 +4,7 @@ const html = htm.bind(h); import { EmojiButton } from 'https://cdn.skypack.dev/@joeattardi/emoji-button'; import ContentEditable from './content-editable.js'; -import { generatePlaceholderText, getCaretPosition } from '../../utils/chat.js'; +import { generatePlaceholderText, getCaretPosition, convertToText, convertOnPaste } from '../../utils/chat.js'; import { getLocalStorage, setLocalStorage } from '../../utils/helpers.js'; import { URL_CUSTOM_EMOJIS, KEY_CHAT_FIRST_MESSAGE_SENT } from '../../utils/constants.js'; @@ -199,8 +199,7 @@ export default class ChatInput extends Component { } handlePaste(event) { - event.preventDefault(); - document.execCommand('inserttext', false, event.clipboardData.getData('text/plain')); + convertOnPaste(event); } handleSubmitChatButton(event) { @@ -211,7 +210,7 @@ export default class ChatInput extends Component { sendMessage() { const { handleSendMessage } = this.props; const { hasSentFirstChatMessage, inputHTML } = this.state; - const message = inputHTML.trim(); + const message = convertToText(inputHTML); const newStates = { inputWarning: '', inputHTML: '', diff --git a/webroot/js/utils/chat.js b/webroot/js/utils/chat.js index 209f61ff3..54ad19c54 100644 --- a/webroot/js/utils/chat.js +++ b/webroot/js/utils/chat.js @@ -1,4 +1,3 @@ -import { addNewlines } from './helpers.js'; import { CHAT_INITIAL_PLACEHOLDER_TEXT, CHAT_PLACEHOLDER_TEXT, @@ -20,7 +19,7 @@ export function formatMessageText(message, username) { formattedText = linkify(formattedText, message); formattedText = highlightUsername(formattedText, username); - return addNewlines(formattedText); + return convertToMarkup(formattedText); } function highlightUsername(message, username) { @@ -188,3 +187,94 @@ export function extraUserNamesFromMessageHistory(messages) { } return list; } + + +// utils from https://gist.github.com/nathansmith/86b5d4b23ed968a92fd4 +/* + You would call this after getting an element's + `.innerHTML` value, while the user is typing. +*/ +export function convertToText(str = '') { + // Ensure string. + let value = String(str); + + // Convert encoding. + value = value.replace(/ /gi, ' '); + value = value.replace(/&/gi, '&'); + + // Replace `
`. + value = value.replace(/
/gi, '\n'); + + // Replace `
` (from Chrome). + value = value.replace(/
/gi, '\n'); + + // Replace `

` (from IE). + value = value.replace(/

/gi, '\n'); + + // Remove extra tags. + value = value.replace(/<(.*?)>/g, ''); + + // Trim each line. + value = value + .split('\n') + .map((line = '') => { + return line.trim(); + }) + .join('\n'); + + // No more than 2x newline, per "paragraph". + value = value.replace(/\n\n+/g, '\n\n'); + + // Clean up spaces. + value = value.replace(/[ ]+/g, ' '); + value = value.trim(); + + // Expose string. + return value; +} + +/* + You would call this when receiving a plain text + value back from an API, and before inserting the + text into the `contenteditable` area on a page. +*/ +export function convertToMarkup(str = '') { + return convertToText(str).replace(/\n/g, '
'); +} + +/* + You would call this when a user pastes from + the clipboard into a `contenteditable` area. +*/ +export function convertOnPaste( event = { preventDefault() {} }) { + // Prevent paste. + event.preventDefault(); + + // Set later. + let value = ''; + + // Does method exist? + const hasEventClipboard = !!( + event.clipboardData && + typeof event.clipboardData === 'object' && + typeof event.clipboardData.getData === 'function' + ); + + // Get clipboard data? + if (hasEventClipboard) { + value = event.clipboardData.getData('text/plain'); + } + + // Insert into temp `