aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/formattedText/FormattedTextBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx')
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx358
1 files changed, 185 insertions, 173 deletions
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 40acf164f..f07c2d191 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -21,16 +21,16 @@ import { List } from '../../../../fields/List';
import { PrefetchProxy } from '../../../../fields/Proxy';
import { RichTextField } from '../../../../fields/RichTextField';
import { ComputedField } from '../../../../fields/ScriptField';
-import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DateCast, DocCast, FieldValue, NumCast, RTFCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivWidth, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT';
import { DocServer } from '../../../DocServer';
import { Docs, DocUtils } from '../../../documents/Documents';
import { CollectionViewType } from '../../../documents/DocumentTypes';
import { DictationManager } from '../../../util/DictationManager';
import { DocumentManager } from '../../../util/DocumentManager';
-import { DragManager } from '../../../util/DragManager';
+import { DragManager, dropActionType } from '../../../util/DragManager';
import { MakeTemplate } from '../../../util/DropConverter';
import { LinkManager } from '../../../util/LinkManager';
import { RTFMarkup } from '../../../util/RTFMarkup';
@@ -51,7 +51,7 @@ import { SidebarAnnos } from '../../SidebarAnnos';
import { StyleProp } from '../../StyleProvider';
import { media_state } from '../AudioBox';
import { DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView';
-import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView';
+import { FieldView, FieldViewProps, FocusViewOptions } from '../FieldView';
import { LinkInfo } from '../LinkDocPreview';
import { PinProps, PresBox } from '../trails';
import { DashDocCommentView } from './DashDocCommentView';
@@ -70,8 +70,13 @@ import { SummaryView } from './SummaryView';
import { isDarkMode } from '../../../util/reportManager/reportManagerUtils';
import Select from 'react-select';
// import * as applyDevTools from 'prosemirror-dev-tools';
+
+interface FormattedTextBoxProps extends FieldViewProps {
+ onBlur?: () => void; // callback when text loses focus
+ autoFocus?: boolean; // whether text should get input focus when created
+}
@observer
-export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
+export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextBoxProps>() implements ViewBoxInterface {
public static LayoutString(fieldStr: string) {
return FieldView.LayoutString(FormattedTextBox, fieldStr);
}
@@ -88,7 +93,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
private _sidebarRef = React.createRef<SidebarAnnos>();
private _sidebarTagRef = React.createRef<React.Component>();
private _ref: React.RefObject<HTMLDivElement> = React.createRef();
- private _scrollRef: React.RefObject<HTMLDivElement> = React.createRef();
+ private _scrollRef: HTMLDivElement | null = null;
private _editorView: Opt<EditorView>;
public _applyingChange: string = '';
private _inDrop = false;
@@ -101,8 +106,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
private _dropDisposer?: DragManager.DragDropDisposer;
private _recordingStart: number = 0;
private _ignoreScroll = false;
- private _lastText = '';
- private _hadDownFocus = false;
private _focusSpeed: Opt<number>;
private _keymap: any = undefined;
private _rules: RichTextRules | undefined;
@@ -203,7 +206,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return url.startsWith(document.location.origin) ? new URL(url).pathname.split('doc/').lastElement() : ''; // docId
}
- constructor(props: FieldViewProps) {
+ constructor(props: FormattedTextBoxProps) {
super(props);
makeObservable(this);
FormattedTextBox.Instance = this;
@@ -245,8 +248,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
- if (!pinProps && this._editorView?.state.selection.empty) return this.Document;
- const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.Document.title), annotationOn: this.Document });
+ const rootDoc = Doc.isTemplateDoc(this._props.docViewPath().lastElement()?.Document) ? this.Document : DocCast(this.Document.rootDocument, this.Document);
+ if (!pinProps && this._editorView?.state.selection.empty) return rootDoc;
+ const anchor = Docs.Create.ConfigDocument({ title: StrCast(rootDoc.title), annotationOn: rootDoc });
this.addDocument(anchor);
this._finishingLink = true;
this.makeLinkAnchor(anchor, OpenWhere.addRight, undefined, 'Anchored Selection', false, addAsAnnotation);
@@ -274,29 +278,24 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
let stopFunc: any;
const targetData = target[DocData];
targetData.mediaState = media_state.Recording;
- targetData.audioAnnoState = 'recording';
DocumentViewInternal.recordAudioAnnotation(targetData, Doc.LayoutFieldKey(target), stop => (stopFunc = stop));
- let reactionDisposer = reaction(
+ const reactionDisposer = reaction(
() => target.mediaState,
- action(dictation => {
+ dictation => {
if (!dictation) {
- targetData.audioAnnoState = 'stopped';
stopFunc();
reactionDisposer();
}
- })
+ }
);
target.title = ComputedField.MakeFunction(`self["text_audioAnnotations_text"].lastElement()`);
}
});
};
- AnchorMenu.Instance.Highlight = undoable(
- action((color: string, isLinkButton: boolean) => {
- this._editorView?.state && RichTextMenu.Instance.setHighlight(color);
- return undefined;
- }),
- 'highlght text'
- );
+ AnchorMenu.Instance.Highlight = undoable((color: string) => {
+ this._editorView?.state && RichTextMenu.Instance?.setHighlight(color);
+ return undefined;
+ }, 'highlght text');
AnchorMenu.Instance.onMakeAnchor = () => this.getAnchor(true);
AnchorMenu.Instance.StartCropDrag = unimplementedFunction;
/**
@@ -307,7 +306,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
e.preventDefault();
e.stopPropagation();
const targetCreator = (annotationOn?: Doc) => {
- const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn);
+ const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, annotationOn);
FormattedTextBox.SetSelectOnLoad(target);
return target;
};
@@ -329,8 +328,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
leafText = (node: Node) => {
if (node.type === this._editorView?.state.schema.nodes.dashField) {
- const refDoc = !node.attrs.docId ? this.Document : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc);
- return Field.toJavascriptString(refDoc[node.attrs.fieldKey as string] as Field);
+ const refDoc = !node.attrs.docId ? DocCast(this.Document.rootDocument, this.Document) : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc);
+ const fieldKey = StrCast(node.attrs.fieldKey);
+ return (
+ (node.attrs.hideKey ? '' : fieldKey + ':') + //
+ (node.attrs.hideValue ? '' : Field.toJavascriptString(refDoc[fieldKey] as Field))
+ );
}
return '';
};
@@ -345,12 +348,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
tryUpdateDoc = (force: boolean) => {
if (this._editorView && (this._editorView as any).docView) {
const state = this._editorView.state;
- const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
+ const dataDoc = this.dataDoc;
const newText = state.doc.textBetween(0, state.doc.content.size, ' \n', this.leafText);
const newJson = JSON.stringify(state.toJSON());
const prevData = Cast(this.layoutDoc[this.fieldKey], RichTextField, null); // the actual text in the text box
const templateData = this.Document !== this.layoutDoc ? prevData : undefined; // the default text stored in a layout template
const protoData = Cast(Cast(dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype
+ const layoutData = this.layoutDoc.isTemplateDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField, null) : undefined; // the default text inherited from a prototype
const effectiveAcl = GetEffectiveAcl(dataDoc);
const removeSelection = (json: string | undefined) => json?.replace(/"selection":.*/, '');
@@ -367,24 +371,24 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
let unchanged = true;
- if (this._applyingChange !== this.fieldKey && (force || removeSelection(newJson) !== removeSelection(prevData?.Data))) {
+ const textChange = newText !== prevData?.Text; // the Text string can change even if the RichText doesn't because dashFieldViews may return new strings as the data they reference changes
+ if (this._applyingChange !== this.fieldKey && (force || textChange || removeSelection(newJson) !== removeSelection(prevData?.Data))) {
this._applyingChange = this.fieldKey;
- const textChange = newText !== prevData?.Text;
textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
- if ((!prevData && !protoData) || newText || (!newText && !protoData)) {
+ if ((!prevData && !protoData && !layoutData) || newText || (!newText && !protoData && !layoutData)) {
// if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
- if (force || ((this._finishingLink || this._props.isContentActive() || this._inDrop) && removeSelection(newJson) !== removeSelection(prevData?.Data))) {
+ if (force || ((this._finishingLink || this._props.isContentActive() || this._inDrop) && (textChange || removeSelection(newJson) !== removeSelection(prevData?.Data)))) {
const numstring = NumCast(dataDoc[this.fieldKey], null);
- dataDoc[this.fieldKey] = numstring !== undefined ? Number(newText) : new RichTextField(newJson, newText);
- dataDoc[this.fieldKey + '_noTemplate'] = true; // mark the data field as being split from the template if it has been edited
+ dataDoc[this.fieldKey] =
+ numstring !== undefined ? Number(newText) : newText || (DocCast(dataDoc.proto)?.[this.fieldKey] === undefined && this.layoutDoc[this.fieldKey] === undefined) ? new RichTextField(newJson, newText) : undefined;
textChange && ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.Document, text: newText });
+ this._applyingChange = ''; // turning this off here allows a Doc to retrieve data from template if noTemplate below is changed to false
unchanged = false;
}
} else {
// if we've deleted all the text in a note driven by a template, then restore the template data
dataDoc[this.fieldKey] = undefined;
- this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((protoData || prevData).Data)));
- dataDoc[this.fieldKey + '_noTemplate'] = undefined; // mark the data field as not being split from any template it might have
+ this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse(((layoutData !== prevData ? layoutData : undefined) ?? protoData).Data)));
ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, text: newText });
unchanged = false;
}
@@ -450,16 +454,23 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
autoLink = () => {
const newAutoLinks = new Set<Doc>();
- const oldAutoLinks = LinkManager.Links(this.Document).filter(link => link.link_relationship === LinkManager.AutoKeywords);
+ const oldAutoLinks = LinkManager.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))) ||
+ (Doc.isTemplateForField(this.Document) && (link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document))) &&
+ link.link_relationship === LinkManager.AutoKeywords
+ ); // prettier-ignore
if (this._editorView?.state.doc.textContent) {
- const isNodeSel = this._editorView.state.selection instanceof NodeSelection;
const f = this._editorView.state.selection.from;
+
const t = this._editorView.state.selection.to;
var tr = this._editorView.state.tr as any;
const autoAnch = this._editorView.state.schema.marks.autoLinkAnchor;
tr = tr.removeMark(0, tr.doc.content.size, autoAnch);
- Doc.MyPublishedDocs.forEach(term => (tr = this.hyperlinkTerm(tr, term, newAutoLinks)));
- tr = tr.setSelection(isNodeSel && false ? new NodeSelection(tr.doc.resolve(f)) : new TextSelection(tr.doc.resolve(f), tr.doc.resolve(t)));
+ Doc.MyPublishedDocs.filter(term => term.title).forEach(term => (tr = this.hyperlinkTerm(tr, term, newAutoLinks)));
+ tr = tr.setSelection(new TextSelection(tr.doc.resolve(f), tr.doc.resolve(t)));
this._editorView?.dispatch(tr);
}
oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.link_anchor_2 !== this.Document).forEach(LinkManager.Instance.deleteLink);
@@ -469,7 +480,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
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
- (title.startsWith('-') || title.startsWith('@')) &&
+ title.startsWith('-') &&
this._editorView &&
!this.dataDoc.title_custom &&
(Doc.LayoutFieldKey(this.Document) === this.fieldKey || this.fieldKey === 'text')
@@ -477,14 +488,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
let node = this._editorView.state.doc;
while (node.firstChild && node.firstChild.type.name !== 'text') node = node.firstChild;
const str = node.textContent;
- const prefix = str.startsWith('@') ? '' : '-';
+ const prefix = '-';
const cfield = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc.title));
if (!(cfield instanceof ComputedField)) {
this.dataDoc.title = (prefix + str.substring(0, Math.min(40, str.length)) + (str.length > 40 ? '...' : '')).trim();
- if (str.startsWith('@') && str.length > 1) {
- Doc.AddToMyPublished(this.Document);
- }
}
}
};
@@ -501,7 +509,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
hyperlinkTerm = (tr: any, target: Doc, newAutoLinks: Set<Doc>) => {
const editorView = this._editorView;
if (editorView && (editorView as any).docView && !Doc.AreProtosEqual(target, this.Document)) {
- const autoLinkTerm = StrCast(target.title).replace(/^@/, '');
+ const autoLinkTerm = Field.toString(target.title as Field).replace(/^@/, '');
var alink: Doc | undefined;
this.findInNode(editorView, editorView.state.doc, autoLinkTerm).forEach(sel => {
if (
@@ -624,7 +632,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
docId: draggedDoc[Id],
float: 'unset',
});
- if (!['embed', 'copy'].includes((dropAction ?? '') as any)) {
+ if (!de.embedKey && ![dropActionType.embed, dropActionType.copy].includes(dropAction ?? dropActionType.move)) {
added = dragData.removeDocument?.(draggedDoc) ? true : false;
} else {
added = true;
@@ -748,7 +756,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
const hr = Math.round(Date.now() / 1000 / 60 / 60);
numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-hr-' + (hr - i), { opacity: ((10 - i - 1) / 10).toString() }));
}
- this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css changes happen outside of react/mobx. so we need to set a flag that will notify anyone intereted in layout changes triggered by css changes (eg., CollectionLinkView)
+ this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css changes happen outside of react/mobx. so we need to set a flag that will notify anyone interested in layout changes triggered by css changes (eg., CollectionLinkView)
};
@observable _showSidebar = false;
@@ -759,7 +767,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
@action
toggleSidebar = (preview: boolean = false) => {
const defaultSidebar = 250;
- const prevWidth = 1 - this.sidebarWidth() / Number(getComputedStyle(this._ref.current!).width.replace('px', ''));
+ const prevWidth = 1 - this.sidebarWidth() / DivWidth(this._ref.current!);
if (preview) this._showSidebar = true;
else {
this.layoutDoc[this.SidebarKey + '_freeform_scale_max'] = 1;
@@ -878,7 +886,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
event: undoBatch(() => {
this.dataDoc.layout_meta = Cast(Doc.UserDoc().emptyHeader, Doc, null)?.layout;
this.Document.layout_fieldKey = 'layout_meta';
- setTimeout(() => (this.layoutDoc._headerHeight = this.layoutDoc._layout_autoHeightMargins = 50), 50);
+ setTimeout(() => (this.layoutDoc._header_height = this.layoutDoc._layout_autoHeightMargins = 50), 50);
}),
icon: 'eye',
});
@@ -940,9 +948,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
description: 'Make Default Layout',
event: () => {
if (!this.layoutDoc.isTemplateDoc) {
- const title = StrCast(this.Document.title);
- this.Document.title = 'text';
- MakeTemplate(this.Document, true, title);
+ MakeTemplate(this.Document);
}
Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.Document);
Doc.AddDocToList(Cast(Doc.UserDoc().template_notes, Doc, null), 'data', this.Document);
@@ -953,6 +959,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
const options = cm.findByDescription('Options...');
const optionItems = options && 'subitems' in options ? options.subitems : [];
+ optionItems.push({ description: `Toggle auto update from template`, event: () => (this.dataDoc[this.fieldKey + '_autoUpdate'] = !this.dataDoc[this.fieldKey + '_autoUpdate']), icon: 'star' });
optionItems.push({ description: `Generate Dall-E Image`, event: () => this.generateImage(), icon: 'star' });
optionItems.push({ description: `Ask GPT-3`, event: () => this.askGPT(), icon: 'lightbulb' });
this._props.renderDepth &&
@@ -967,8 +974,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
event: () => (this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight),
icon: this.Document._layout_autoHeight ? 'lock' : 'unlock',
});
- optionItems.push({ description: `show markdown options`, event: RTFMarkup.Instance.open, icon: <BsMarkdownFill /> });
!options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' });
+ const help = cm.findByDescription('Help...');
+ const helpItems = help && 'subitems' in help ? help.subitems : [];
+ helpItems.push({ description: `show markdown options`, event: RTFMarkup.Instance.open, icon: <BsMarkdownFill /> });
+ !help && cm.addItem({ description: 'Help...', subitems: helpItems, icon: 'eye' });
this._downX = this._downY = Number.NaN;
};
@@ -1012,7 +1022,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
const state = this._editorView.state;
const to = state.selection.to;
const updated = TextSelection.create(state.doc, to, to);
- this._editorView.dispatch(state.tr.setSelection(updated).insertText('\n', to));
+ this._editorView.dispatch(state.tr.setSelection(updated).insert(to, state.schema.nodes.paragraph.create({})));
if (this._recordingDictation) {
this.recordDictation();
}
@@ -1212,7 +1222,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
this._cachedLinks = LinkManager.Links(this.Document);
this._disposers.breakupDictation = reaction(() => Doc.RecordingEvent, this.breakupDictation);
this._disposers.layout_autoHeight = reaction(
- () => ({ autoHeight: this.layout_autoHeight, fontSize: this.fontSize }),
+ () => ({ autoHeight: this.layout_autoHeight, fontSize: this.fontSize, css: this.Document[DocCss] }),
(autoHeight, fontSize) => setTimeout(() => autoHeight && this.tryUpdateScrollHeight())
);
this._disposers.highlights = reaction(
@@ -1259,9 +1269,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
);
this._disposers.editorState = reaction(
() => {
- const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc?.proto), this.fieldKey) ? DocCast(this.layoutDoc?.proto) : this?.dataDoc;
- const whichDoc = !this.dataDoc || !this.layoutDoc ? undefined : dataDoc?.[this.fieldKey + '_noTemplate'] || !this.layoutDoc[this.fieldKey] ? dataDoc : this.layoutDoc;
- return !whichDoc ? undefined : { data: Cast(whichDoc[this.fieldKey], RichTextField, null), str: Field.toString(DocCast(whichDoc[this.fieldKey]) ?? StrCast(whichDoc[this.fieldKey])) };
+ const protoData = DocCast(this.dataDoc.proto)?.[this.fieldKey];
+ 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 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)) };
},
incomingValue => {
if (this._editorView && this._applyingChange !== this.fieldKey) {
@@ -1271,11 +1287,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
this._editorView.updateState(EditorState.fromJSON(this.config, updatedState));
this.tryUpdateScrollHeight();
}
- } else if (incomingValue?.str) {
- selectAll(this._editorView.state, tx => this._editorView?.dispatch(tx.insertText(incomingValue.str)));
+ } else if (this._editorView.state.doc.textContent !== incomingValue?.str) {
+ selectAll(this._editorView.state, tx => this._editorView?.dispatch(tx.insertText(incomingValue?.str ?? '')));
}
}
- }
+ },
+ { fireImmediately: true }
);
this._disposers.search = reaction(
@@ -1313,25 +1330,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
);
if (this._recordingDictation) setTimeout(this.recordDictation);
}
- var quickScroll: string | undefined = '';
this._disposers.scroll = reaction(
() => NumCast(this.layoutDoc._layout_scrollTop),
pos => {
- if (!this._ignoreScroll && this._scrollRef.current && !this._props.dontSelectOnLoad) {
- const viewTrans = quickScroll ?? StrCast(this.Document._viewTransition);
- const durationMiliStr = viewTrans.match(/([0-9]*)ms/);
- const durationSecStr = viewTrans.match(/([0-9.]*)s/);
- const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
- if (duration) {
- this._scrollStopper = smoothScroll(duration, this._scrollRef.current, Math.abs(pos || 0), 'ease', this._scrollStopper);
- } else {
- this._scrollRef.current.scrollTo({ top: pos });
- }
+ if (!this._ignoreScroll && this._scrollRef) {
+ const durationStr = StrCast(this.Document._viewTransition).match(/([0-9]+)(m?)s/);
+ const duration = Number(durationStr?.[1]) * (durationStr?.[2] ? 1 : 1000);
+ this._scrollStopper = smoothScroll(duration || 0, this._scrollRef, Math.abs(pos || 0), 'ease', this._scrollStopper);
}
},
{ fireImmediately: true }
);
- quickScroll = undefined;
this.tryUpdateScrollHeight();
setTimeout(this.tryUpdateScrollHeight, 250);
}
@@ -1371,15 +1380,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
DocServer.GetRefField(pdfAnchorId).then(pdfAnchor => {
if (pdfAnchor instanceof Doc) {
const dashField = view.state.schema.nodes.paragraph.create({}, [
- view.state.schema.nodes.dashField.create({ fieldKey: 'text', docId: pdfAnchor[Id], hideKey: true, editable: false }, undefined, [
+ view.state.schema.nodes.dashField.create({ fieldKey: 'text', docId: pdfAnchor[Id], hideKey: true, hideValue: false, editable: false }, undefined, [
view.state.schema.marks.linkAnchor.create({
allAnchors: [{ href: `/doc/${this.Document[Id]}`, title: this.Document.title, anchorId: `${this.Document[Id]}` }],
- title: `from: ${DocCast(pdfAnchor.embedContainer).title}`,
+ title: StrCast(pdfAnchor.title),
noPreview: true,
- docref: false,
+ docref: true,
+ fontSize: '8px',
}),
- view.state.schema.marks.pFontSize.create({ fontSize: '8px' }),
- view.state.schema.marks.em.create({}),
]),
]);
@@ -1424,14 +1432,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
handleScrollToSelection: editorView => {
const docPos = editorView.coordsAtPos(editorView.state.selection.to);
const viewRect = self._ref.current!.getBoundingClientRect();
- const scrollRef = self._scrollRef.current;
+ const scrollRef = self._scrollRef;
const topOff = docPos.top < viewRect.top ? docPos.top - viewRect.top : undefined;
const botOff = docPos.bottom > viewRect.bottom ? docPos.bottom - viewRect.bottom : undefined;
if (((topOff && Math.abs(Math.trunc(topOff)) > 0) || (botOff && Math.abs(Math.trunc(botOff)) > 0)) && scrollRef) {
const shift = Math.min(topOff ?? Number.MAX_VALUE, botOff ?? Number.MAX_VALUE);
const scrollPos = scrollRef.scrollTop + shift * self.ScreenToLocalBoxXf().Scale;
if (this._focusSpeed !== undefined) {
- scrollPos && (this._scrollStopper = smoothScroll(this._focusSpeed, scrollRef, scrollPos, 'ease', this._scrollStopper));
+ setTimeout(() => scrollPos && (this._scrollStopper = smoothScroll(this._focusSpeed || 0, scrollRef, scrollPos, 'ease', this._scrollStopper)));
} else {
scrollRef.scrollTo({ top: scrollPos });
}
@@ -1482,39 +1490,38 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.Document, FormattedTextBox.SelectOnLoad) && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()));
- if (this._editorView && selectOnLoad && !this._props.dontRegisterView && !this._props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
- const selLoadChar = FormattedTextBox.SelectOnLoadChar;
+ const selLoadChar = FormattedTextBox.SelectOnLoadChar;
+ if (selectOnLoad) {
FormattedTextBox.SelectOnLoad = undefined;
+ FormattedTextBox.SelectOnLoadChar = '';
+ }
+ if (this._editorView && selectOnLoad && !this._props.dontRegisterView && !this._props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
this._props.select(false);
if (selLoadChar) {
const $from = this._editorView.state.selection.anchor ? this._editorView.state.doc.resolve(this._editorView.state.selection.anchor - 1) : undefined;
const mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) });
const curMarks = this._editorView.state.storedMarks ?? $from?.marksAcross(this._editorView.state.selection.$head) ?? [];
const storedMarks = [...curMarks.filter(m => m.type !== mark.type), mark];
- const tr = this._editorView.state.tr
- .setStoredMarks(storedMarks)
- .insertText(FormattedTextBox.SelectOnLoadChar, this._editorView.state.doc.content.size - 1, this._editorView.state.doc.content.size)
- .setStoredMarks(storedMarks);
+ const tr1 = this._editorView.state.tr.setStoredMarks(storedMarks);
+ const tr2 = selLoadChar === 'Enter' ? tr1.insert(this._editorView.state.doc.content.size - 1, schema.nodes.paragraph.create()) : tr1.insertText(selLoadChar, this._editorView.state.doc.content.size - 1);
+ const tr = tr2.setStoredMarks(storedMarks);
+
this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
} else if (curText && !FormattedTextBox.DontSelectInitialText) {
selectAll(this._editorView.state, this._editorView?.dispatch);
}
}
- selectOnLoad && this._editorView!.focus();
+ if (selectOnLoad) {
+ FormattedTextBox.DontSelectInitialText = false;
+ this._editorView!.focus();
+ }
if (this._props.isContentActive()) this.prepareForTyping();
- if (this._editorView) {
- const tr = this._editorView.state.tr;
- const { from, to } = tr.selection;
- // for some reason, the selection is sometimes lost in the sidebar view when prosemirror syncs the seledtion with the dom, so reset the selection after the document has ben fully instantiated.
- if (FormattedTextBox.DontSelectInitialText) setTimeout(() => this._editorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(from), tr.doc.resolve(to)))), 250);
-
- if (FormattedTextBox.PasteOnLoad) {
- const pdfAnchorId = FormattedTextBox.PasteOnLoad.clipboardData?.getData('dash/pdfAnchor');
- FormattedTextBox.PasteOnLoad = undefined;
- pdfAnchorId && this.addPdfReference(pdfAnchorId);
- }
+ if (this._editorView && FormattedTextBox.PasteOnLoad) {
+ const pdfAnchorId = FormattedTextBox.PasteOnLoad.clipboardData?.getData('dash/pdfAnchor');
+ FormattedTextBox.PasteOnLoad = undefined;
+ pdfAnchorId && this.addPdfReference(pdfAnchorId);
}
- FormattedTextBox.DontSelectInitialText = false;
+ if (this._props.autoFocus) setTimeout(() => this._editorView!.focus()); // not sure why setTimeout is needed but editing dashFieldView's doesn't work without it.
}
// add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet.
@@ -1587,7 +1594,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
(this.ProseRef?.children?.[0] as any).focus();
}
}
- this._hadDownFocus = this.ProseRef?.children[0].className.includes('focused') ?? false;
if (e.button === 2 || (e.button === 0 && e.ctrlKey)) {
e.preventDefault();
}
@@ -1596,23 +1602,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
document.removeEventListener('pointerup', this.onSelectEnd);
};
onPointerUp = (e: React.PointerEvent): void => {
- const editor = this._editorView!;
- const state = editor?.state;
- if (!Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime) && !this._hadDownFocus) {
- (this.ProseRef?.children[0] as HTMLElement)?.blur?.();
- }
- if (!state || !editor || !this.ProseRef?.children[0].className.includes('-focused')) return;
- if (!state.selection.empty && !(state.selection instanceof NodeSelection)) this.setupAnchorMenu();
- else if (this._props.isContentActive()) {
- const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
- let xpos = pcords?.pos || 0;
- while (xpos > 0 && !state.doc.resolve(xpos).node()?.isTextblock) {
- xpos = xpos - 1;
- }
- editor.dispatch(state.tr.setSelection(new TextSelection(state.doc.resolve(xpos))));
+ const state = this.EditorView?.state;
+ if (state && this.ProseRef?.children[0].className.includes('-focused') && this._props.isContentActive() && !e.button) {
+ if (!state.selection.empty && !(state.selection instanceof NodeSelection)) this.setupAnchorMenu();
let target = e.target as any; // hrefs are stored on the dataset of the <a> node that wraps the hyerlink <span>
+ for (let target = e.target as any; target && !target.dataset?.targethrefs; target = target.parentElement);
while (target && !target.dataset?.targethrefs) target = target.parentElement;
- FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview === 'true');
+ FormattedTextBoxComment.update(this, this.EditorView!, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview === 'true');
}
};
@action
@@ -1633,10 +1629,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
e.stopPropagation();
}
};
- setFocus = () => {
- const pos = this._editorView?.state.selection.$from.pos || 1;
- (this.ProseRef?.children?.[0] as any).focus();
- setTimeout(() => this._editorView?.dispatch(this._editorView?.state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos))));
+ setFocus = (ipos?: number) => {
+ const pos = ipos ?? (this._editorView?.state.selection.$from.pos || 1);
+ setTimeout(() => this._editorView?.dispatch(this._editorView.state.tr.setSelection(TextSelection.near(this._editorView.state.doc.resolve(pos)))), 100);
+ setTimeout(() => (this.ProseRef?.children?.[0] as any).focus(), 200);
};
@action
onFocused = (e: React.FocusEvent): void => {
@@ -1688,10 +1684,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
this._forceUncollapse = false;
clearStyleSheetRules(FormattedTextBox._bulletStyleSheet);
const clickPos = this._editorView!.posAtCoords({ left: x, top: y });
- let olistPos = clickPos?.pos;
+ const clickPosVal = clickPos?.pos || 1;
+ let olistPos = clickPosVal;
if (clickPos && olistPos && this._props.rootSelected?.()) {
- const clickNode = this._editorView?.state.doc.nodeAt(olistPos);
- const nodeBef = this._editorView?.state.doc.nodeAt(Math.max(0, olistPos - 1));
+ const clickNode = this._editorView?.state.doc.resolve(olistPos).node();
+ const nodeBef = this._editorView?.state.doc.resolve(Math.max(0, olistPos - 1)).node();
olistPos = nodeBef?.type === this._editorView?.state.schema.nodes.ordered_list ? olistPos - 1 : olistPos;
let $olistPos = this._editorView?.state.doc.resolve(olistPos);
let olistNode = (nodeBef !== null || clickNode?.type === this._editorView?.state.schema.nodes.list_item) && olistPos === clickPos?.pos ? clickNode : nodeBef;
@@ -1701,18 +1698,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
$olistPos = this._editorView?.state.doc.resolve(($olistPos as any).path[($olistPos as any).path.length - 4]);
}
}
- const listPos = this._editorView?.state.doc.resolve(clickPos.pos);
- const listNode = this._editorView?.state.doc.nodeAt(clickPos.pos);
+ const maxSize = this._editorView?.state.doc.content.size ?? 0;
+ const listPos = this._editorView?.state.doc.resolve(Math.min(maxSize, clickPosVal === olistPos ? clickPosVal + 1 : clickPosVal));
+ const listNode = listPos?.node();
if (olistNode && olistNode.type === this._editorView?.state.schema.nodes.ordered_list && listNode) {
if (!highlightOnly) {
if (selectOrderedList) {
this._editorView.dispatch(this._editorView.state.tr.setSelection(new NodeSelection(selectOrderedList ? $olistPos! : listPos!)));
} else {
- const tr = this._editorView.state.tr.setNodeMarkup(clickPos.pos, listNode.type, { ...listNode.attrs, visibility: !listNode.attrs.visibility });
- this._editorView.dispatch(tr.setSelection(TextSelection.create(tr.doc, clickPos.pos)));
+ const nodePos = clickPosVal - (olistPos === clickPosVal ? 0 : 1);
+ if (this._editorView.state.doc.nodeAt(nodePos)) {
+ const tr = this._editorView.state.tr.setNodeMarkup(nodePos, listNode.type, { ...listNode.attrs, visibility: !listNode.attrs.visibility });
+ this._editorView.dispatch(tr.setSelection(TextSelection.create(tr.doc, nodePos)));
+ }
}
}
- addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ':hover:before', { background: 'lightgray' });
+ addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ':hover:before', { background: 'gray' });
}
}
}
@@ -1729,33 +1730,38 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (this.ProseRef?.children[0] !== e.nativeEvent.target) return;
if (!(this.EditorView?.state.selection instanceof NodeSelection) || this.EditorView.state.selection.node.type !== this.EditorView.state.schema.nodes.footnote) {
const stordMarks = this._editorView?.state.storedMarks?.slice();
- this.autoLink();
- if (this._editorView?.state.tr) {
- const tr = stordMarks?.reduce((tr, m) => {
- tr.addStoredMark(m);
- return tr;
- }, this._editorView.state.tr);
- tr && this._editorView.dispatch(tr);
+ if (!(this.EditorView?.state.selection instanceof NodeSelection)) {
+ this.autoLink();
+ if (this._editorView?.state.tr) {
+ const tr = stordMarks?.reduce((tr, m) => {
+ tr.addStoredMark(m);
+ return tr;
+ }, this._editorView.state.tr);
+ tr && this._editorView.dispatch(tr);
+ }
}
}
if (RichTextMenu.Instance?.view === this._editorView && !this._props.rootSelected?.()) {
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, undefined);
}
FormattedTextBox._hadSelection = window.getSelection()?.toString() !== '';
+
+ // this is the markdown for @<published name> document publishing to Doc.myPublishedDocs
+ const match = RTFCast(this.Document[this.fieldKey])?.Text.match(/^(@[a-zA-Z][a-zA-Z_0-9 -]*[a-zA-Z_0-9-]+)/);
+ if (match) {
+ this.dataDoc.title_custom = true;
+ this.dataDoc.title = match[1]; // this triggers the collectionDockingView to publish this Doc
+ this.EditorView?.dispatch(this.EditorView?.state.tr.deleteRange(0, match[1].length + 1));
+ }
+
this.endUndoTypingBatch();
FormattedTextBox.LiveTextUndo?.end();
FormattedTextBox.LiveTextUndo = undefined;
const state = this._editorView!.state;
- if (StrCast(this.Document.title).startsWith('@') && !this.dataDoc.title_custom) {
- UndoManager.RunInBatch(() => {
- this.dataDoc.title_custom = true;
- this.dataDoc.layout_showTitle = 'title';
- const tr = this._editorView!.state.tr;
- this._editorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(0), tr.doc.resolve(StrCast(this.Document.title).length + 2))).deleteSelection());
- }, 'titler');
- }
+ // if the text box blurs and none of its contents are focused(), then pass the blur along
+ setTimeout(() => !this.ProseRef?.contains(document.activeElement) && this._props.onBlur?.());
};
onKeyDown = (e: React.KeyboardEvent) => {
@@ -1788,7 +1794,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
this._editorView!.dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from, state.selection.from)));
(document.activeElement as any).blur?.();
SelectionManager.DeselectAll();
- RichTextMenu.Instance.updateMenu(undefined, undefined, undefined, undefined);
+ RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, undefined);
return;
case 'Enter':
this.insertTime();
@@ -1801,7 +1807,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
default:
if (this._lastTimedMark?.attrs.userid === Doc.CurrentUserEmail) break;
case ' ':
- if (e.code !== 'Space') {
+ if (e.code !== 'Space' && e.code !== 'Backspace') {
[AclEdit, AclAugment, AclAdmin].includes(GetEffectiveAcl(this.Document)) &&
this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark).addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })));
}
@@ -1815,28 +1821,28 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
e.stopPropagation(); // drag n drop of text within text note will generate a new note if not caughst, as will dragging in from outside of Dash.
};
onScroll = (e: React.UIEvent) => {
- if (!LinkInfo.Instance?.LinkInfo && this._scrollRef.current) {
- if (!this._props.dontSelectOnLoad) {
- this._ignoreScroll = true;
- this.layoutDoc._layout_scrollTop = this._scrollRef.current.scrollTop;
- this._ignoreScroll = false;
- e.stopPropagation();
- e.preventDefault();
- }
+ if (!LinkInfo.Instance?.LinkInfo && this._scrollRef) {
+ this._ignoreScroll = true;
+ this.layoutDoc._layout_scrollTop = this._scrollRef.scrollTop;
+ this._ignoreScroll = false;
+ e.stopPropagation();
+ e.preventDefault();
}
};
tryUpdateScrollHeight = () => {
const margins = 2 * NumCast(this.layoutDoc._yMargin, this._props.yPadding || 0);
const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined;
if (children && !SnappingManager.IsDragging) {
- const toNum = (val: string) => Number(val.replace('px', '').replace('auto', '0'));
- const toHgt = (node: Element) => {
+ const getChildrenHeights = (kids: Element[] | undefined) => kids?.reduce((p, child) => p + toHgt(child), margins) ?? 0;
+ const toNum = (val: string) => Number(val.replace('px', ''));
+ const toHgt = (node: Element): number => {
const { height, marginTop, marginBottom } = getComputedStyle(node);
- return toNum(height) + Math.max(0, toNum(marginTop)) + Math.max(0, toNum(marginBottom));
+ const childHeight = height === 'auto' ? getChildrenHeights(Array.from(node.children)) : toNum(height);
+ return childHeight + Math.max(0, toNum(marginTop)) + Math.max(0, toNum(marginBottom));
};
- const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + toHgt(child), margins);
+ const proseHeight = !this.ProseRef ? 0 : getChildrenHeights(children);
const scrollHeight = this.ProseRef && proseHeight;
- if (this._props.setHeight && scrollHeight && !this._props.dontRegisterView) {
+ if (this._props.setHeight && !this._props.suppressSetHeight && scrollHeight && !this._props.dontRegisterView) {
// if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
const setScrollHeight = () => (this.dataDoc[this.fieldKey + '_scrollHeight'] = scrollHeight);
@@ -1960,11 +1966,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
</div>
);
}
- cycleAlternateText = () => {
- if (this.layoutDoc._layout_enableAltContentUI) {
- const usePath = this.layoutDoc[`_${this._props.fieldKey}_usePath`];
- this.layoutDoc[`_${this._props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined;
- }
+ cycleAlternateText = (skipHover?: boolean) => {
+ this.layoutDoc._layout_enableAltContentUI = true;
+ const usePath = this.layoutDoc[`_${this._props.fieldKey}_usePath`];
+ this.layoutDoc[`_${this._props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' && !skipHover ? 'alternate:hover' : undefined;
};
@computed get overlayAlternateIcon() {
const usePath = this.layoutDoc[`_${this._props.fieldKey}_usePath`];
@@ -1999,7 +2004,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
);
}
get fieldKey() {
- const usePath = StrCast(this.layoutDoc[`${this._props.fieldKey}_usePath`]);
+ return this._fieldKey;
+ }
+ @computed get _fieldKey() {
+ const usePath = this._props.ignoreUsePath ? '' : StrCast(this.layoutDoc[`${this._props.fieldKey}_usePath`]);
return this._props.fieldKey + (usePath && (!usePath.includes(':hover') || this._isHovering || this._props.isContentActive()) ? `_${usePath.replace(':hover', '')}` : '');
}
@observable _isHovering = false;
@@ -2016,11 +2024,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
// if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
if (this._props.isContentActive()) {
const scale = this._props.NativeDimScaling?.() || 1;
- const styleFromLayoutString = Doc.styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._headerHeight}px' >
+ const styleFromLayoutString = Doc.styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._header_height}px' >
const height = Number(styleFromLayoutString.height?.replace('px', ''));
// prevent default if selected || child is active but this doc isn't scrollable
if (
- (this._scrollRef.current?.scrollHeight ?? 0) <= Math.ceil((height ? height : this._props.PanelHeight()) / scale) && //
+ !Number.isNaN(height) &&
+ (this._scrollRef?.scrollHeight ?? 0) <= Math.ceil((height ? height : this._props.PanelHeight()) / scale) && //
(this._props.rootSelected?.() || this.isAnyChildContentActive())
) {
e.preventDefault();
@@ -2048,12 +2057,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
setTimeout(() => !this._props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide);
const paddingX = NumCast(this.layoutDoc._xMargin, this._props.xPadding || 0);
const paddingY = NumCast(this.layoutDoc._yMargin, this._props.yPadding || 0);
- const styleFromLayoutString = Doc.styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._headerHeight}px' >
+ const styleFromLayoutString = Doc.styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._header_height}px' >
return styleFromLayoutString?.height === '0px' ? null : (
<div
className="formattedTextBox"
- onPointerEnter={action(() => (this._isHovering = true))}
- onPointerLeave={action(() => (this._isHovering = false))}
+ onPointerEnter={action(() => {
+ this._isHovering = true;
+ this.layoutDoc[`_${this._props.fieldKey}_usePath`] && (this.Document.isHovering = true);
+ })}
+ onPointerLeave={action(() => (this.Document.isHovering = this._isHovering = false))}
ref={r => {
this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
this._oldWheel = r;
@@ -2095,15 +2107,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
onDoubleClick={this.onDoubleClick}>
<div
className="formattedTextBox-outer"
- ref={this._scrollRef}
+ ref={r => (this._scrollRef = r)}
style={{
- width: this._props.dontSelectOnLoad || this.noSidebar ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`,
+ width: this.noSidebar ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`,
overflow: this.layoutDoc._createDocOnCR ? 'hidden' : this.layoutDoc._layout_autoHeight ? 'visible' : undefined,
}}
onScroll={this.onScroll}
onDrop={this.ondrop}>
<div
- className={`formattedTextBox-inner${rounded} ${this.layoutDoc.layout_centered ? 'centered' : ''}`}
+ className={`formattedTextBox-inner${rounded} ${this.layoutDoc._layout_centered ? 'centered' : ''}`}
ref={this.createDropTarget}
style={{
padding: StrCast(this.layoutDoc._textBoxPadding),
@@ -2114,8 +2126,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}}
/>
</div>
- {this.noSidebar || this._props.dontSelectOnLoad || !this.SidebarShown || this.layout_sidebarWidthPercent === '0%' ? null : this.sidebarCollection}
- {this.noSidebar || this.Document._layout_noSidebar || this._props.dontSelectOnLoad || this.Document._createDocOnCR || this.layoutDoc._chromeHidden ? null : this.sidebarHandle}
+ {this.noSidebar || !this.SidebarShown || this.layout_sidebarWidthPercent === '0%' ? null : this.sidebarCollection}
+ {this.noSidebar || this.Document._layout_noSidebar || this.Document._createDocOnCR || this.layoutDoc._chromeHidden ? null : this.sidebarHandle}
{this.audioHandle}
{this.layoutDoc._layout_enableAltContentUI && !this.layoutDoc._chromeHidden ? this.overlayAlternateIcon : null}
</div>