diff options
Diffstat (limited to 'src/fields/RichTextField.ts')
-rw-r--r-- | src/fields/RichTextField.ts | 60 |
1 files changed, 53 insertions, 7 deletions
diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts index 3f13f7e6d..bcef1fefc 100644 --- a/src/fields/RichTextField.ts +++ b/src/fields/RichTextField.ts @@ -13,14 +13,19 @@ export class RichTextField extends ObjectField { @serializable(true) readonly Text: string; - constructor(data: string, text: string = '') { + /** + * NOTE: if 'text' doesn't match the plain text of 'data', this can cause infinite loop problems or other artifacts when rendered. + * @param data this is the formatted text representation of the RTF + * @param text this is the plain text of whatever text is in the 'data' + */ + constructor(data: string, text: string) { super(); this.Data = data; - this.Text = text; + this.Text = text; // ideally, we'd compute 'text' from 'data' by doing what Prosemirror does at run-time ... just need to figure out how to write that function accurately } Empty() { - return !(this.Text || this.Data.toString().includes('dashField') || this.Data.toString().includes('align')); + return !(this.Text || this.Data.toString().includes('dashField') || this.Data.toString().includes('dashDoc') || this.Data.toString().includes('align')); } [Copy]() { @@ -37,10 +42,51 @@ export class RichTextField extends ObjectField { return this.Text; } - public static RTFfield() { - return new RichTextField( - `{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}`, - '' + // AARAV ADD= + static ToProsemirrorDoc = (content: Record<string, unknown>[], selection: Record<string, unknown>) => ({ + doc: { + type: 'doc', + content, + }, + selection, + }); + + private static ToProsemirrorTextContent = (text: string, styles?: { bold?: boolean; italic?: boolean; fontSize?: number; color?: string }) => [ + { + type: 'text', + marks: [ + ...(styles?.bold ? [{ type: 'strong' }] : []), + ...(styles?.italic ? [{ type: 'em' }] : []), + ...(styles?.fontSize ? [{ type: 'pFontSize', attrs: { fontSize: `${styles.fontSize}px` } }] : []), + ...(styles?.color ? [{ type: 'pFontColor', attrs: { fontColor: styles.color } }] : []), + ], + text, + }, + ]; + + private static ToProsemirrorDashDocContent = (docId: string) => [ + { + type: 'dashDoc', + attrs: { width: '200px', height: '200px', title: 'dashDoc', float: 'unset', hidden: false, docId }, + }, + ]; + + private static ToProsemirror = (plaintext: string, imgDocId?: string, styles?: { bold?: boolean; italic?: boolean; fontSize?: number; color?: string }, selectBack?: number) => + RichTextField.ToProsemirrorDoc( + plaintext + .split('\n') + .filter(text => (imgDocId ? text : true)) // if there's an image doc, we don't want it repeat for each paragraph -- assume there's only one paragraph with text in it + .map(text => ({ + type: 'paragraph', + content: [ + ...(text.length ? RichTextField.ToProsemirrorTextContent(text, styles) : []), // An empty paragraph gets treated as a line break + ...(imgDocId ? RichTextField.ToProsemirrorDashDocContent(imgDocId) : []), + ], + })), + { type: 'text', anchor: 2 + plaintext.length - (selectBack ?? 0), head: 2 + plaintext.length } ); + + public static textToRtf(text: string, imgDocId?: string, styles?: { bold?: boolean; italic?: boolean; fontSize?: number; color?: string }, selectBack?: number) { + return new RichTextField(JSON.stringify(RichTextField.ToProsemirror(text, imgDocId, styles, selectBack)), text); } } |