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.tsx47
1 files changed, 27 insertions, 20 deletions
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index a6870d65b..eb1f9d07b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -131,9 +131,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
private _forceUncollapse = true; // if the cursor doesn't move between clicks, then the selection will disappear for some reason. This flags the 2nd click as happening on a selection which allows bullet points to toggle
private _break = true;
- public _applyingChange: string = '';
public ProseRef?: HTMLDivElement;
+ /**
+ * ApplyingChange - Marks whether an interactive text edit is currently in the process of being written to the database.
+ * This is needed to distinguish changes to text fields caused by editing vs those caused by changes to
+ * the prototype or other external edits
+ */
+ public ApplyingChange: string = '';
+
@observable _showSidebar = false;
@computed get fontColor() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontColor) as string; } // prettier-ignore
@@ -359,8 +365,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
let unchanged = true;
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
const rtField = (layoutData !== prevData ? layoutData : undefined) ?? protoData;
- if (this._applyingChange !== this.fieldKey && (force || textChange || removeSelection(newJson) !== removeSelection(prevData?.Data))) {
- this._applyingChange = this.fieldKey;
+ if (this.ApplyingChange !== this.fieldKey && (force || textChange || removeSelection(newJson) !== removeSelection(prevData?.Data))) {
+ this.ApplyingChange = this.fieldKey;
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) && (textChange || removeSelection(newJson) !== removeSelection(prevData?.Data)))) {
@@ -370,7 +376,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
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
+ 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 (rtField) {
@@ -381,7 +387,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, text: newText });
unchanged = false;
}
- this._applyingChange = '';
+ this.ApplyingChange = '';
if (!unchanged) {
this.updateTitle();
this.tryUpdateScrollHeight();
@@ -1012,7 +1018,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (i.className !== 'ProseMirror-separator') this.getImageDesc(i.src);
}
}
- // console.log('HI' + this.ProseRef?.getElementsByTagName('img'));
};
getImageDesc = async (u: string) => {
@@ -1315,7 +1320,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return !whichData ? undefined : { data: RTFCast(whichData), str: Field.toString(DocCast(whichData) ?? StrCast(whichData)) };
},
incomingValue => {
- if (this.EditorView && this._applyingChange !== this.fieldKey) {
+ if (this.EditorView && this.ApplyingChange !== this.fieldKey) {
if (incomingValue?.data) {
const updatedState = JSON.parse(incomingValue.data.Data);
if (JSON.stringify(this.EditorView.state.toJSON()) !== JSON.stringify(updatedState)) {
@@ -1405,7 +1410,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
// } catch (err) {
// console.log('Drop failed', err);
// }
- // console.log('LKSDFLJ');
this.addDocument?.(DocCast(this.Document.image));
}
@@ -1695,10 +1699,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
setTimeout(() => (this.ProseRef?.children?.[0] as HTMLElement).focus(), 200);
};
- IsFocused = false;
@action
onFocused = (e: React.FocusEvent): void => {
- this.IsFocused = true;
// applyDevTools.applyDevTools(this.EditorView);
e.stopPropagation();
};
@@ -1780,18 +1782,23 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
this._undoTyping = undefined;
}
- @action
- onBlur = (e: React.FocusEvent) => {
- let ele: HTMLElement | null = e.relatedTarget instanceof HTMLElement ? e.relatedTarget : null;
- if (ele?.tabIndex === -1) {
- for (; ele; ele = ele?.parentElement) {
- if (ele?.className === 'fonticonbox') {
- setTimeout(() => this._ref.current?.focus());
- break;
- }
+ /**
+ * When a text box loses focus, it might be because a text button was clicked (eg, bold, italics) or color picker.
+ * In these cases, force focus back onto the text box.
+ * @param target
+ */
+ tryKeepingFocus = (target: Element | null) => {
+ for (let newFocusEle = target instanceof HTMLElement ? target : null; newFocusEle; newFocusEle = newFocusEle?.parentElement) {
+ // test if parent of new focused element is a UI button (should be more specific than testing className)
+ if (newFocusEle?.className === 'fonticonbox' || newFocusEle?.className === 'popup-container') {
+ return this.EditorView?.focus(); // keep focus on text box
}
}
- if (ele?.className !== 'fonticonbox') this.IsFocused = false;
+ };
+
+ @action
+ onBlur = (e: React.FocusEvent) => {
+ this.tryKeepingFocus(e.relatedTarget);
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();