mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-04-04 23:03:45 -04:00
Remove trailing empty paragraphs
This commit is contained in:
@@ -1,20 +1,15 @@
|
||||
import {
|
||||
getText,
|
||||
getSchema,
|
||||
getTextSerializersFromSchema,
|
||||
JSONContent,
|
||||
} from '@tiptap/core'
|
||||
import { Node as ProseMirrorNode } from '@tiptap/pm/model'
|
||||
import { StarterKit } from '@tiptap/starter-kit'
|
||||
import { Image } from '@tiptap/extension-image'
|
||||
import { Link } from '@tiptap/extension-link'
|
||||
import { Mention } from '@tiptap/extension-mention'
|
||||
import {getSchema, getText, getTextSerializersFromSchema, JSONContent,} from '@tiptap/core'
|
||||
import {Node as ProseMirrorNode} from '@tiptap/pm/model'
|
||||
import {StarterKit} from '@tiptap/starter-kit'
|
||||
import {Image} from '@tiptap/extension-image'
|
||||
import {Link} from '@tiptap/extension-link'
|
||||
import {Mention} from '@tiptap/extension-mention'
|
||||
import Iframe from './tiptap-iframe'
|
||||
import { find } from 'linkifyjs'
|
||||
import { uniq } from 'lodash'
|
||||
import { compareTwoStrings } from 'string-similarity'
|
||||
import {find} from 'linkifyjs'
|
||||
import {uniq} from 'lodash'
|
||||
import {compareTwoStrings} from 'string-similarity'
|
||||
|
||||
/** get first url in text. like "notion.so " -> "http://notion.so"; "notion" -> null */
|
||||
/** get first url in text. like "notion.so " -> "http://notion.so" "notion" -> null */
|
||||
export function getUrl(text: string) {
|
||||
const results = find(text, 'url')
|
||||
return results.length ? results[0].href : null
|
||||
@@ -48,10 +43,10 @@ export function parseMentions(data: JSONContent): string[] {
|
||||
export const extensions = [
|
||||
StarterKit,
|
||||
Link,
|
||||
Image.extend({ renderText: () => '[image]' }),
|
||||
Image.extend({renderText: () => '[image]'}),
|
||||
Mention, // user @mention
|
||||
Iframe.extend({
|
||||
renderText: ({ node }) =>
|
||||
renderText: ({node}) =>
|
||||
'[embed]' + node.attrs.src ? `(${node.attrs.src})` : '',
|
||||
}),
|
||||
]
|
||||
@@ -78,8 +73,59 @@ export function parseJsonContentToText(content: JSONContent | string) {
|
||||
}
|
||||
|
||||
export function urlBase64ToUint8Array(base64String: string) {
|
||||
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
|
||||
const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');
|
||||
const rawData = window.atob(base64);
|
||||
return new Uint8Array([...rawData].map(c => c.charCodeAt(0)));
|
||||
}
|
||||
const padding = '='.repeat((4 - (base64String.length % 4)) % 4)
|
||||
const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/')
|
||||
const rawData = window.atob(base64)
|
||||
return new Uint8Array([...rawData].map(c => c.charCodeAt(0)))
|
||||
}
|
||||
|
||||
export function cleanDoc(doc: JSONContent) {
|
||||
if (!doc || !Array.isArray(doc.content)) return doc;
|
||||
|
||||
let content = [...doc.content];
|
||||
|
||||
const isEmptyParagraph = (node: JSONContent) =>
|
||||
node.type === "paragraph" &&
|
||||
(!node.content || node.content.length === 0);
|
||||
|
||||
// Remove empty paragraphs at the start
|
||||
while (content.length > 0 && isEmptyParagraph(content[0])) {
|
||||
content.shift();
|
||||
}
|
||||
|
||||
// Remove empty paragraphs at the end
|
||||
while (content.length > 0 && isEmptyParagraph(content[content.length - 1])) {
|
||||
content.pop();
|
||||
}
|
||||
|
||||
// Trim leading/trailing hardBreaks within first and last paragraphs
|
||||
const trimHardBreaks = (paragraph: JSONContent) => {
|
||||
if (!paragraph.content) return paragraph;
|
||||
|
||||
let nodes = [...paragraph.content];
|
||||
|
||||
// Remove hardBreaks at the start
|
||||
while (nodes.length > 0 && nodes[0].type === "hardBreak") {
|
||||
nodes.shift();
|
||||
}
|
||||
|
||||
// Remove hardBreaks at the end
|
||||
while (nodes.length > 0 && nodes[nodes.length - 1].type === "hardBreak") {
|
||||
nodes.pop();
|
||||
}
|
||||
|
||||
return { ...paragraph, content: nodes };
|
||||
};
|
||||
|
||||
if (content.length > 0) {
|
||||
content[0] = trimHardBreaks(content[0]);
|
||||
if (content.length > 1) {
|
||||
content[content.length - 1] = trimHardBreaks(content[content.length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any now-empty paragraphs created by hardBreak trimming
|
||||
content = content.filter(node => !(node.type === "paragraph" && (!node.content || node.content.length === 0)));
|
||||
|
||||
return { ...doc, content };
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ import {useGroupedMessages, usePaginatedScrollingMessages,} from 'web/lib/supaba
|
||||
import {PrivateMessageChannel} from 'common/supabase/private-messages'
|
||||
import {ChatMessage} from 'common/chat-message'
|
||||
import {BackButton} from 'web/components/back-button'
|
||||
import {SEO} from "web/components/SEO";
|
||||
import {SEO} from "web/components/SEO"
|
||||
import {cleanDoc} from "common/util/parse";
|
||||
|
||||
export default function PrivateMessagesPage() {
|
||||
const router = useRouter()
|
||||
@@ -183,8 +184,8 @@ export const PrivateChat = (props: {
|
||||
setIsSubmitting(true)
|
||||
|
||||
try {
|
||||
const content = editor.getJSON();
|
||||
// console.log('editingMessage submitting message', {editingMessage}, JSON.stringify(content))
|
||||
const content = cleanDoc(editor.getJSON())
|
||||
// console.log('submitting message', JSON.stringify(content))
|
||||
if (editingMessage) {
|
||||
// console.log('editingMessage edit-message', editingMessage)
|
||||
setMessages((prevMessages) =>
|
||||
|
||||
Reference in New Issue
Block a user