aboutsummaryrefslogtreecommitdiff
path: root/src/fields/RichTextField.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/fields/RichTextField.ts')
-rw-r--r--src/fields/RichTextField.ts87
1 files changed, 69 insertions, 18 deletions
diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts
index dc636031a..4b1403b88 100644
--- a/src/fields/RichTextField.ts
+++ b/src/fields/RichTextField.ts
@@ -48,26 +48,77 @@ export class RichTextField extends ObjectField {
''
);
}
+ static Initialize = (initial?: string) => {
+ const content: object[] = [];
+ const state = {
+ doc: {
+ type: 'doc',
+ content,
+ },
+ selection: {
+ type: 'text',
+ anchor: 0,
+ head: 0,
+ },
+ };
+ if (initial && initial.length) {
+ content.push({
+ type: 'paragraph',
+ content: {
+ type: 'text',
+ text: initial,
+ },
+ });
+ state.selection.anchor = state.selection.head = initial.length + 1;
+ }
+ return JSON.stringify(state);
+ };
+
+ private static ToProsemirrorState = (plainText: string, selectBack?: number, delimeter = '\n') => {
+ // Remap the text, creating blocks split on newlines
+ const elements = plainText.split(delimeter);
+
+ // Google Docs adds in an extra carriage return automatically, so this counteracts it
+ !elements[elements.length - 1].length && elements.pop();
+
+ // Preserve the current state, but re-write the content to be the blocks
+ const parsed: Record<string, unknown> = JSON.parse(RichTextField.Initialize());
+ (parsed.doc as Record<string, unknown>).content = elements.map(text => {
+ const paragraph: object = {
+ type: 'paragraph',
+ content: text.length ? [{ type: 'text', marks: [], text }] : undefined, // An empty paragraph gets treated as a line break
+ };
+ return paragraph;
+ });
- public static textToRtf(text: string, imgDocId?: string) {
+ // If the new content is shorter than the previous content and selection is unchanged, may throw an out of bounds exception, so we reset it
+ parsed.selection = { type: 'text', anchor: 2 + plainText.length - (selectBack ?? 0), head: 2 + plainText.length };
+
+ // Export the ProseMirror-compatible state object we've just built
+ return JSON.stringify(parsed);
+ };
+
+ public static textToRtf(text: string, imgDocId?: string, selectBack?: number) {
return new RichTextField(
- JSON.stringify({
- // this is a RichText json that has the question text placed above a related image
- doc: {
- type: 'doc',
- content: [
- {
- type: 'paragraph',
- attrs: { align: 'center', color: null, id: null, indent: null, inset: null, lineSpacing: null, paddingBottom: null, paddingTop: null },
- content: [
- ...(text ? [{ type: 'text', text }] : []), //
- ...(imgDocId ? [{ type: 'dashDoc', attrs: { width: '200px', height: '200px', title: 'dashDoc', float: 'unset', hidden: false, docId: imgDocId } }] : []),
- ],
- },
- ],
- },
- selection: { type: 'text', anchor: 2, head: 2 },
- }),
+ !imgDocId
+ ? this.ToProsemirrorState(text, selectBack)
+ : JSON.stringify({
+ // this is a RichText json that has the question text placed above a related image
+ doc: {
+ type: 'doc',
+ content: [
+ {
+ type: 'paragraph',
+ attrs: { align: 'center', color: null, id: null, indent: null, inset: null, lineSpacing: null, paddingBottom: null, paddingTop: null },
+ content: [
+ ...(text ? [{ type: 'text', text }] : []), //
+ ...(imgDocId ? [{ type: 'dashDoc', attrs: { width: '200px', height: '200px', title: 'dashDoc', float: 'unset', hidden: false, docId: imgDocId } }] : []),
+ ],
+ },
+ ],
+ },
+ selection: { type: 'text', anchor: 2 + text.length, head: 2 + text.length },
+ }),
text
);
}