diff --git a/src/components/editor/CustomEditor.vue b/src/components/editor/CustomEditor.vue
index afb7e99..7711510 100644
--- a/src/components/editor/CustomEditor.vue
+++ b/src/components/editor/CustomEditor.vue
@@ -123,11 +123,16 @@ const handleInput = (event) => {
- const isEmpty = textContent === '' &&
- !target.querySelector('img, .editor-file, .mention')
-
- if (isEmpty && target.innerHTML !== '') {
- target.innerHTML = ''
+ const editorNode = target;
+ const currentNormalizedHtml = editorNode.innerHTML.trim().toLowerCase().replace(/\s+/g, '');
+
+ const hasTextContent = editorNode.textContent.trim() !== '';
+ const hasSpecialElements = editorNode.querySelector('img, .editor-file, .mention');
+
+ if (!hasTextContent && !hasSpecialElements) {
+ if (currentNormalizedHtml !== '' && currentNormalizedHtml !== '
') {
+ editorNode.innerHTML = '';
+ }
}
@@ -344,6 +349,36 @@ const handlePaste = (event) => {
}
+// Helper function to insert line break
+const insertLineBreak = (range) => {
+ const editor = editorRef.value;
+ if (!editor) return;
+
+ const br = document.createElement('br');
+ range.deleteContents(); // Clear selected content or collapsed cursor position
+ range.insertNode(br);
+
+ // Create a zero-width space or a text node to ensure the cursor can be placed after the
+ // and that the
is not immediately removed by cleanup logic if it's the only content.
+ const nbsp = document.createTextNode('\u200B'); // Zero-width space
+ range.setStartAfter(br);
+ range.insertNode(nbsp);
+ range.setStartAfter(nbsp);
+ range.collapse(true);
+
+ const selection = window.getSelection();
+ if (selection) {
+ selection.removeAllRanges();
+ selection.addRange(range);
+ }
+
+ // Ensure editor focus and trigger input handling
+ editor.focus();
+ nextTick(() => {
+ handleInput({ target: editor });
+ });
+};
+
const handleKeydown = (event) => {
if (showMention.value) {
@@ -531,45 +566,61 @@ const handleKeydown = (event) => {
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey || event.shiftKey)) {
-
- const selection = window.getSelection()
- if (selection && selection.rangeCount > 0) {
- const range = selection.getRangeAt(0)
- const br = document.createElement('br')
- range.deleteContents()
- range.insertNode(br)
-
-
- const textNode = document.createTextNode('')
- range.setStartAfter(br)
- range.insertNode(textNode)
- range.setStartAfter(textNode)
- range.collapse(true)
- selection.removeAllRanges()
- selection.addRange(range)
-
-
- handleInput({ target: editorRef.value })
+ event.preventDefault();
+
+ const editor = editorRef.value;
+ if (!editor) return;
+
+ const selection = window.getSelection();
+ if (!selection || selection.rangeCount === 0) {
+ // 如果没有选区,尝试聚焦并创建选区
+ editor.focus();
+ // 等待DOM更新
+ nextTick(() => {
+ const newSelection = window.getSelection();
+ if (newSelection && newSelection.rangeCount > 0) {
+ insertLineBreak(newSelection.getRangeAt(0));
+ }
+ });
+ return;
}
-
-
- event.preventDefault()
- return
+
+ insertLineBreak(selection.getRangeAt(0));
+ return;
}
+
+
+
if (event.key === 'Enter' && !event.ctrlKey && !event.metaKey && !event.shiftKey) {
- event.preventDefault()
-
-
- const editor = editorRef.value
- const quoteElement = editor?.querySelector('.editor-quote')
- if (!quoteElement && quoteData.value) {
- quoteData.value = null
+ event.preventDefault();
+
+ const editor = editorRef.value;
+ if (!editor) return;
+
+ const messageData = parseEditorContent();
+ const isEmptyMessage = messageData.items.length === 0 ||
+ (messageData.items.length === 1 &&
+ messageData.items[0].type === 1 &&
+ !messageData.items[0].content.trimEnd());
+
+ if (isEmptyMessage) {
+ // If the message is considered empty, prevent sending.
+ // Ensure editor is truly empty if it wasn't already.
+ if (editor.innerHTML !== '') {
+ clearEditor();
+ }
+ return;
}
-
-
- sendMessage()
+
+ // If message is not empty, proceed to send.
+ const quoteElement = editor.querySelector('.editor-quote');
+ if (!quoteElement && quoteData.value) {
+ quoteData.value = null;
+ }
+
+ sendMessage();
}
}
@@ -592,10 +643,15 @@ const sendMessage = () => {
}
messageData.items.forEach(item => {
- if (item.type === 1 && cleanInvisibleChars(item.content.trimEnd())) {
+ if (item.type === 1 && cleanInvisibleChars(item.content).trimEnd()) { // Apply trimEnd after cleaning
+ const finalContent = cleanInvisibleChars(item.content).replace(/
/gi, '\n').trimEnd();
+ if (!finalContent && !messageData.mentionUids.length && !messageData.quoteId) {
+ // If after processing, the content is empty and no mentions/quote, skip
+ return;
+ }
const data = {
items: [{
- content: cleanInvisibleChars(item.content),
+ content: finalContent, // Use the processed content
type: 1
}],
mentionUids: messageData.mentionUids,
@@ -655,36 +711,30 @@ const parseEditorContent = () => {
const processNode = (node) => {
if (node.nodeType === Node.TEXT_NODE) {
-
- textContent += node.textContent
- return
+ textContent += node.textContent;
+ return;
}
-
- if (node.nodeType !== Node.ELEMENT_NODE) return
-
-
- if (node.classList.contains('mention')) {
-
- const userId = node.getAttribute('data-user-id')
+
+ if (node.nodeType !== Node.ELEMENT_NODE) return;
+
+ if (node.tagName === 'BR') {
+ textContent += '\n';
+ } else if (node.classList.contains('mention')) {
+ const userId = node.getAttribute('data-user-id');
if (userId) {
- mentionUids.push(Number(userId))
+ mentionUids.push(Number(userId));
}
- textContent += node.textContent
+ textContent += node.textContent;
} else if (node.tagName === 'IMG') {
-
- processImage(node)
+ processImage(node);
} else if (node.classList.contains('emoji')) {
-
- textContent += node.getAttribute('alt') || node.textContent
+ textContent += node.getAttribute('alt') || node.textContent;
} else if (node.classList.contains('editor-file')) {
-
- processFile(node)
+ processFile(node);
} else if (node.childNodes.length) {
-
- Array.from(node.childNodes).forEach(processNode)
+ Array.from(node.childNodes).forEach(processNode);
} else {
-
- textContent += node.textContent
+ textContent += node.textContent;
}
}
@@ -758,11 +808,11 @@ const parseEditorContent = () => {
Array.from(tempDiv.childNodes).forEach(processNode)
- if (textContent.trim()) {
+ if (textContent) {
items.push({
type: 1,
- content: textContent.trimEnd()
- })
+ content: textContent
+ });
}
diff --git a/src/utils/auth.js b/src/utils/auth.js
index aeaeb1b..7dcbede 100644
--- a/src/utils/auth.js
+++ b/src/utils/auth.js
@@ -18,7 +18,7 @@ export function isLoggedIn() {
*/
export function getAccessToken() {
// return storage.get(AccessToken) || ''
- return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b891a491a664540c3af42964b31bedf8b1c93e8a754bb71e4b95d53ad8e6b16ac1575f536a9e7a062e44f3bb48a367623d38bd875a10afa3a53e79374ffda424138ed9ad4cab0d972432567ae7149b2bf3c'
+ return JSON.parse(localStorage.getItem('token'))||'79b5c732d96d2b27a48a99dfd4a5566c43aaa5796242e854ebe3ffc198d6876b9628e7b764d9af65ab5dbb2d517ced88170491b74b048c0ba827c0d3741462cb89dc59ed46653a449af837a8262941caaef1334d640773710f8cd96473bacfb190cba595a5d6a9c87d70f0999a3ebb41147213b31b4bdccffca66a56acf3baab5af0154f0dce360079f37709f78e13711036899344bddb0fb4cf0f2890287cb62c3fcbe33368caa5e213624577be8b8420ab75b1f50775ee16142a4321c5d56995f37354a66a969da98d95ba6e65d142ed097e04b411c1ebad2f62866d0ec7e1838420530a9941dbbcd00490199f8b8993ebccf0349a53e3197efc45b9dbe3f2bf1dc0dddce6787811964e76efefec3b3fd39fce15d43989c156413f12de3f0c74c1ff1d3c5da214d3bcefef7546498e37fa73453c749a56ea66777488bd3550'
}
/**