aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/formattedText
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/formattedText')
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx55
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx6
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts19
3 files changed, 43 insertions, 37 deletions
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index cfb6dfa12..dc23a695d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -214,9 +214,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
- const rootDoc = Doc.isTemplateDoc(this._props.docViewPath().lastElement()?.Document) ? this.Document : this.rootDoc;
- if (!pinProps && this.EditorView?.state.selection.empty) return rootDoc;
- const anchor = Docs.Create.ConfigDocument({ title: StrCast(rootDoc.title), annotationOn: rootDoc });
+ if (!pinProps && this.EditorView?.state.selection.empty) return this.rootDoc;
+ const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.rootDoc?.title), annotationOn: this.rootDoc });
this.addDocument(anchor);
this._finishingLink = true;
this.makeLinkAnchor(anchor, OpenWhere.addRight, undefined, 'Anchored Selection', false, addAsAnnotation);
@@ -245,7 +244,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
anchor.followLinkAudio = true;
let stopFunc: () => void = emptyFunction;
target.$mediaState = mediaState.Recording;
- DictationManager.recordAudioAnnotation(target, Doc.LayoutFieldKey(target), stop => { stopFunc = stop }); // prettier-ignore
+ DictationManager.recordAudioAnnotation(target, Doc.LayoutDataKey(target), stop => { stopFunc = stop }); // prettier-ignore
const reactionDisposer = reaction(
() => target.mediaState,
@@ -427,8 +426,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const oldAutoLinks = Doc.Links(this.Document).filter(
link =>
((!Doc.isTemplateForField(this.Document) &&
- (!Doc.isTemplateForField(DocCast(link.link_anchor_1)) || !Doc.AreProtosEqual(DocCast(link.link_anchor_1), this.Document)) &&
- (!Doc.isTemplateForField(DocCast(link.link_anchor_2)) || !Doc.AreProtosEqual(DocCast(link.link_anchor_2), this.Document))) ||
+ ((DocCast(link.link_anchor_1) && !Doc.isTemplateForField(DocCast(link.link_anchor_1)!)) || !Doc.AreProtosEqual(DocCast(link.link_anchor_1), this.Document)) &&
+ ((DocCast(link.link_anchor_2) && !Doc.isTemplateForField(DocCast(link.link_anchor_2)!)) || !Doc.AreProtosEqual(DocCast(link.link_anchor_2), this.Document))) ||
(Doc.isTemplateForField(this.Document) && (link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document))) &&
link.link_relationship === LinkManager.AutoKeywords
); // prettier-ignore
@@ -450,18 +449,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
updateTitle = () => {
const title = StrCast(this.dataDoc.title, Cast(this.dataDoc.title, RichTextField, null)?.Text);
if (
- !this._props.dontRegisterView && // (this.Document.isTemplateForField === "text" || !this.Document.isTemplateForField) && // only update the title if the data document's data field is changing
+ !this._props.dontRegisterView && // only update the title if the data document's data field is changing
title.startsWith('-') &&
this.EditorView &&
!this.dataDoc.title_custom &&
- (Doc.LayoutFieldKey(this.Document) === this.fieldKey || this.fieldKey === 'text')
+ (Doc.LayoutDataKey(this.Document) === this.fieldKey || this.fieldKey === 'text')
) {
let node = this.EditorView.state.doc;
while (node.firstChild && node.firstChild.type.name !== 'text') node = node.firstChild;
const str = node.textContent;
const prefix = '-';
- const cfield = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc.title));
+ const cfield = ComputedField.DisableCompute(() => FieldValue(this.dataDoc.title));
if (!(cfield instanceof ComputedField)) {
this.dataDoc.title = (prefix + str.substring(0, Math.min(40, str.length)) + (str.length > 40 ? '...' : '')).trim();
}
@@ -588,7 +587,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
const dragData = de.complete.docDragData;
if (dragData) {
- const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
+ const layoutProto = DocCast(this.layoutDoc.proto);
+ const dataDoc = layoutProto && Doc.IsDelegateField(layoutProto, this.fieldKey) ? layoutProto : this.dataDoc;
const effectiveAcl = GetEffectiveAcl(dataDoc);
const draggedDoc = dragData.droppedDocuments.lastElement();
let added: Opt<boolean>;
@@ -596,7 +596,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if ([AclEdit, AclAdmin, AclSelfEdit].includes(effectiveAcl) && !dragData.draggedDocuments.includes(this.Document)) {
// replace text contents when dragging with Alt
if (de.altKey) {
- const fieldKey = Doc.LayoutFieldKey(draggedDoc);
+ const fieldKey = Doc.LayoutDataKey(draggedDoc);
if (draggedDoc[fieldKey] instanceof RichTextField && !Doc.AreProtosEqual(draggedDoc, this.Document)) {
Doc.GetProto(this.dataDoc)[this.fieldKey] = Field.Copy(draggedDoc[fieldKey]);
}
@@ -1003,16 +1003,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const link = CreateLinkToActiveAudio(textanchorFunc, false).lastElement();
if (link) {
link.$isDictation = true;
- const audioanchor = Cast(link.link_anchor_2, Doc, null);
- const textanchor = Cast(link.link_anchor_1, Doc, null);
+ const audioanchor = DocCast(link.link_anchor_2);
+ const textanchor = DocCast(link.link_anchor_1);
if (audioanchor) {
audioanchor.backgroundColor = 'tan';
const audiotag = this.EditorView.state.schema.nodes.audiotag.create({
timeCode: NumCast(audioanchor._timecodeToShow),
audioId: audioanchor[Id],
- textId: textanchor[Id],
+ textId: textanchor?.[Id] ?? '',
});
- textanchor.$title = 'dictation:' + audiotag.attrs.timeCode;
+ textanchor && (textanchor.$title = 'dictation:' + audiotag.attrs.timeCode);
const tr = this.EditorView.state.tr.insert(this.EditorView.state.doc.content.size, audiotag);
const tr2 = tr.setSelection(TextSelection.create(tr.doc, tr.doc.content.size));
this.EditorView.dispatch(tr.setSelection(TextSelection.create(tr2.doc, tr2.doc.content.size)));
@@ -1147,11 +1147,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
// if the scroll height has changed and we're in layout_autoHeight mode, then we need to update the textHeight component of the doc.
// Since we also monitor all component height changes, this will update the document's height.
- resetNativeHeight = (scrollHeight: number) => {
- const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.layoutDoc._nativeHeight);
+ resetNativeHeight = action((scrollHeight: number) => {
this.layoutDoc['_' + this.fieldKey + '_height'] = scrollHeight;
- if (nh) this.layoutDoc._nativeHeight = scrollHeight;
- };
+ if (!this.layoutDoc.isTemplateForField) this.layoutDoc._nativeHeight = scrollHeight;
+ });
addPlugin = (plugin: Plugin) => {
const editorView = this.EditorView;
@@ -1216,8 +1215,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const dataData = this.dataDoc[this.fieldKey];
const layoutData = Doc.AreProtosEqual(this.layoutDoc, this.dataDoc) ? undefined : this.layoutDoc[this.fieldKey];
const dataTime = dataData ? (DateCast(this.dataDoc[this.fieldKey + '_modificationDate'])?.date.getTime() ?? 0) : 0;
- const layoutTime = layoutData && this.dataDoc[this.fieldKey + '_autoUpdate'] ? (DateCast(DocCast(this.layoutDoc)[this.fieldKey + '_modificationDate'])?.date.getTime() ?? 0) : 0;
- const protoTime = protoData && this.dataDoc[this.fieldKey + '_autoUpdate'] ? (DateCast(DocCast(this.dataDoc.proto)[this.fieldKey + '_modificationDate'])?.date.getTime() ?? 0) : 0;
+ const layoutTime = layoutData && this.dataDoc[this.fieldKey + '_autoUpdate'] ? (DateCast(DocCast(this.layoutDoc)?.[this.fieldKey + '_modificationDate'])?.date.getTime() ?? 0) : 0;
+ const protoTime = protoData && this.dataDoc[this.fieldKey + '_autoUpdate'] ? (DateCast(DocCast(this.dataDoc.proto)?.[this.fieldKey + '_modificationDate'])?.date.getTime() ?? 0) : 0;
const recentData = dataTime >= layoutTime ? (protoTime >= dataTime ? protoData : dataData) : layoutTime >= protoTime ? layoutData : protoData;
const whichData = recentData ?? (this.layoutDoc.isTemplateDoc ? layoutData : protoData) ?? protoData;
return !whichData ? undefined : { data: RTFCast(whichData), str: Field.toString(DocCast(whichData) ?? StrCast(whichData)) };
@@ -1313,7 +1312,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
// } catch (err) {
// console.log('Drop failed', err);
// }
- this.addDocument?.(DocCast(this.Document.image));
+ DocCast(this.Document.image) && this.addDocument?.(DocCast(this.Document.image)!);
}
//if (this.Document.image) this.addDocument?.(DocCast(this.Document.image));
@@ -1426,8 +1425,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const rtfField = Cast((!curText && this.layoutDoc[this.fieldKey]) || this.dataDoc[fieldKey], RichTextField);
if (this.ProseRef) {
this.EditorView?.destroy();
+ const edState = () => {
+ try {
+ return rtfField?.Data ? EditorState.fromJSON(config, JSON.parse(rtfField.Data)) : EditorState.create(config);
+ } catch {
+ return EditorState.create(config);
+ }
+ };
this._editorView = new EditorView(this.ProseRef, {
- state: rtfField?.Data ? EditorState.fromJSON(config, JSON.parse(rtfField.Data)) : EditorState.create(config),
+ state: edState(),
handleScrollToSelection: this.scrollToSelection,
dispatchTransaction: this.dispatchTransaction,
nodeViews: FormattedTextBox._nodeViews(this),
@@ -1439,7 +1445,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
(this.EditorView as unknown as { scrollToSelection: unknown }).scrollToSelection = this.scrollToSelection;
const { state } = this._editorView;
if (!rtfField) {
- const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
+ const layoutProto = DocCast(this.layoutDoc.proto);
+ const dataDoc = layoutProto && Doc.IsDelegateField(layoutProto, this.fieldKey) ? layoutProto : this.dataDoc;
const startupText = Field.toString(dataDoc[fieldKey] as FieldType);
const textAlign = StrCast(this.dataDoc[this.fieldKey + '_align'], StrCast(Doc.UserDoc().textAlign)) || 'left';
if (textAlign !== 'left') {
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 4fa1fb13b..d31a58030 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -148,11 +148,11 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
this._activeAlignment = this.getActiveAlignment();
this._activeFitBox = BoolCast(refDoc[refField + 'fitBox'], BoolCast(Doc.UserDoc().fitBox));
this._activeFontFamily = !activeFamilies.length
- ? StrCast(this.TextView?.Document._text_fontFamily, StrCast(this.dataDoc?.[Doc.LayoutFieldKey(this.dataDoc) + '_fontFamily'], refVal('fontFamily', 'Arial')))
+ ? StrCast(this.TextView?.Document._text_fontFamily, StrCast(this.dataDoc?.[Doc.LayoutDataKey(this.dataDoc) + '_fontFamily'], refVal('fontFamily', 'Arial')))
: activeFamilies.length === 1
? String(activeFamilies[0])
: 'various';
- this._activeFontSize = !activeSizes.length ? StrCast(this.TextView?.Document.fontSize, StrCast(this.dataDoc?.[Doc.LayoutFieldKey(this.dataDoc) + '_fontSize'], refVal('fontSize', '10px'))) : activeSizes[0];
+ this._activeFontSize = !activeSizes.length ? StrCast(this.TextView?.Document.fontSize, StrCast(this.dataDoc?.[Doc.LayoutDataKey(this.dataDoc) + '_fontSize'], refVal('fontSize', '10px'))) : activeSizes[0];
this._activeFontColor = !activeColors.length ? StrCast(this.TextView?.Document.fontColor, refVal('fontColor', 'black')) : activeColors.length > 0 ? String(activeColors[0]) : '...';
this._activeHighlightColor = !activeHighlights.length ? '' : activeHighlights.length > 0 ? String(activeHighlights[0]) : '...';
@@ -382,7 +382,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
});
}
} else if (this.dataDoc) {
- this.dataDoc[`${Doc.LayoutFieldKey(this.dataDoc)}_${fontField}`] = value;
+ this.dataDoc[`${Doc.LayoutDataKey(this.dataDoc)}_${fontField}`] = value;
this.updateMenu(undefined, undefined, undefined, this.dataDoc);
} else {
Doc.UserDoc()[fontField] = value;
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 14ea911b1..26ccf6931 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -108,25 +108,23 @@ export class RichTextRules {
new InputRule(/>>$/, (state, match, start, end) => {
const numInlines = NumCast(this.Document.$inlineTextCount);
this.Document.$inlineTextCount = numInlines + 1;
- const inlineFieldKey = '$inline' + numInlines; // which field on the text document this annotation will write to
- const inlineLayoutKey = '$layout_' + inlineFieldKey; // the field holding the layout string that will render the inline annotation
+ const inlineFieldKey = 'inline' + numInlines; // which field on the text document this annotation will write to
+ const inlineLayoutKey = 'layout_' + inlineFieldKey; // the field holding the layout string that will render the inline annotation
const textDocInline = Docs.Create.TextDocument('', {
- layout_fieldKey: inlineLayoutKey,
_width: 75,
_height: 35,
- annotationOn: this.Document[DocData],
_layout_fitWidth: true,
_layout_autoHeight: true,
- text_fontSize: '9px',
- title: 'inline comment',
});
+ textDocInline.layout_fieldKey = inlineLayoutKey;
+ textDocInline.annotationOn = this.Document[DocData];
textDocInline.title = inlineFieldKey; // give the annotation its own title
textDocInline.title_custom = true; // And make sure that it's 'custom' so that editing text doesn't change the title of the containing doc
- textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point
+ //textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point
textDocInline.isDataDoc = true;
textDocInline.proto = this.Document[DocData]; // make the annotation inherit from the outer text doc so that it can resolve any nested field references, e.g., [[field]]
- this.Document[inlineLayoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); // create a layout string for the layout key that will render the annotation text
- this.Document[inlineFieldKey] = ''; // set a default value for the annotation
+ this.Document['$' + inlineLayoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); // create a layout string for the layout key that will render the annotation text
+ this.Document['$' + inlineFieldKey] = ''; // set a default value for the annotation
const node = state.doc.resolve(start).nodeAfter;
const newNode = schema.nodes.dashComment.create({ docId: textDocInline[Id], reflow: true });
const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: 'dashDoc', docId: textDocInline[Id], float: 'right' });
@@ -287,7 +285,8 @@ export class RichTextRules {
editor.dispatch(estate.tr.setSelection(new TextSelection(estate.doc.resolve(start), estate.doc.resolve(end - prefixLength))));
}
- DocUtils.MakeLink(this.TextBox.getAnchor(true), target, { link_relationship: 'portal to:portal from' });
+ const tanchor = this.TextBox.getAnchor(true);
+ tanchor && DocUtils.MakeLink(tanchor, target, { link_relationship: 'portal to:portal from' });
const teditor = this.TextBox.EditorView;
if (teditor && selection) {