aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/formattedText
diff options
context:
space:
mode:
authoralyssaf16 <alyssa_feinberg@brown.edu>2024-03-12 16:14:58 -0400
committeralyssaf16 <alyssa_feinberg@brown.edu>2024-03-12 16:14:58 -0400
commit2d9763a63a661420ae0ffa8b4436b29ed717b90b (patch)
tree4c3623c87a6e4e184d06579569fb239cfbad3dc1 /src/client/views/nodes/formattedText
parentecfb0d119e08a101cd8d18e8a90d31995f71eeec (diff)
parent641220e9cd9626af182118f84f8f775d7638cc67 (diff)
Merge branch 'master' into alyssa-starter
Diffstat (limited to 'src/client/views/nodes/formattedText')
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.tsx15
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx67
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx4
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts2
4 files changed, 41 insertions, 47 deletions
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index b49e7dcf0..5c4d850ad 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -4,24 +4,23 @@ import { action, computed, IReactionDisposer, makeObservable, observable, reacti
import { observer } from 'mobx-react';
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
-import Select from 'react-select';
import { Doc, DocListCast, Field } from '../../../../fields/Doc';
import { List } from '../../../../fields/List';
import { listSpec } from '../../../../fields/Schema';
import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField';
-import { Cast, StrCast } from '../../../../fields/Types';
+import { Cast } from '../../../../fields/Types';
import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils';
import { DocServer } from '../../../DocServer';
import { CollectionViewType } from '../../../documents/DocumentTypes';
import { Transform } from '../../../util/Transform';
-import { undoable, undoBatch } from '../../../util/UndoManager';
+import { undoBatch } from '../../../util/UndoManager';
import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu';
import { SchemaTableCell } from '../../collections/collectionSchema/SchemaTableCell';
+import { FilterPanel } from '../../FilterPanel';
import { ObservableReactComponent } from '../../ObservableReactComponent';
import { OpenWhere } from '../DocumentView';
import './DashFieldView.scss';
import { FormattedTextBox } from './FormattedTextBox';
-import { FilterPanel } from '../../FilterPanel';
export class DashFieldView {
dom: HTMLDivElement; // container for label and value
@@ -29,7 +28,7 @@ export class DashFieldView {
node: any;
tbox: FormattedTextBox;
- unclickable = () => !this.tbox._props.isSelected() && this.node.marks.some((m: any) => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview);
+ unclickable = () => !this.tbox._props.rootSelected?.() && this.node.marks.some((m: any) => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview);
constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) {
this.node = node;
this.tbox = tbox;
@@ -108,12 +107,12 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
super(props);
makeObservable(this);
this._fieldKey = this._props.fieldKey;
- this._textBoxDoc = this._props.tbox.Document;
+ this._textBoxDoc = this._fieldKey.startsWith('_') ? this._props.tbox.Document : this._props.tbox.dataDoc;
if (this._props.docId) {
DocServer.GetRefField(this._props.docId).then(action(dashDoc => dashDoc instanceof Doc && (this._dashDoc = dashDoc)));
} else {
- this._dashDoc = this._props.tbox.Document;
+ this._dashDoc = this._fieldKey.startsWith('_') ? this._props.tbox.Document : this._props.tbox.dataDoc;
}
}
@@ -202,7 +201,7 @@ export class DashFieldViewInternal extends ObservableReactComponent<IDashFieldVi
style={{
width: this._props.width,
height: this._props.height,
- pointerEvents: this._props.tbox._props.isSelected() || this._props.tbox.isAnyChildContentActive?.() ? undefined : 'none',
+ pointerEvents: this._props.tbox._props.rootSelected?.() || this._props.tbox.isAnyChildContentActive?.() ? undefined : 'none',
}}>
{this._props.hideKey ? null : (
<span className="dashFieldView-labelSpan" title="click to see related tags" onPointerDown={this.onPointerDownLabelSpan}>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 4250b018e..4fce72cdc 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -23,14 +23,14 @@ import { RichTextField } from '../../../../fields/RichTextField';
import { ComputedField } from '../../../../fields/ScriptField';
import { BoolCast, Cast, DocCast, FieldValue, NumCast, 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';
@@ -67,7 +67,6 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu';
import { RichTextRules } from './RichTextRules';
import { schema } from './schema_rts';
import { SummaryView } from './SummaryView';
-import Select from 'react-select';
// import * as applyDevTools from 'prosemirror-dev-tools';
@observer
export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
@@ -100,7 +99,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;
@@ -306,7 +304,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;
};
@@ -374,9 +372,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
// 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))) {
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 ? 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
+ dataDoc[this.fieldKey + '_noTemplate'] = newText ? true : false; // mark the data field as being split from the template if it has been edited
unchanged = false;
}
} else {
@@ -623,7 +622,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
docId: draggedDoc[Id],
float: 'unset',
});
- if (!['embed', 'copy'].includes((dropAction ?? '') as any)) {
+ if (![dropActionType.embed, dropActionType.copy].includes(dropAction ?? dropActionType.move)) {
added = dragData.removeDocument?.(draggedDoc) ? true : false;
} else {
added = true;
@@ -747,7 +746,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;
@@ -758,7 +757,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;
@@ -948,9 +947,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);
@@ -1201,7 +1198,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(
@@ -1467,39 +1464,37 @@ 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;
}
// 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.
@@ -1588,7 +1583,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
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()) {
+ else if (this._props.isContentActive() && !e.button) {
const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
let xpos = pcords?.pos || 0;
while (xpos > 0 && !state.doc.resolve(xpos).node()?.isTextblock) {
@@ -2031,7 +2026,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
render() {
TraceMobx();
- const scale = (this._props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
+ const scale = this._props.NativeDimScaling?.() || 1; // * NumCast(this.layoutDoc._freeform_scale, 1);
const rounded = StrCast(this.layoutDoc.layout_borderRounding) === '100%' ? '-rounded' : '';
setTimeout(() => !this._props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide);
const paddingX = NumCast(this.layoutDoc._xMargin, this._props.xPadding || 0);
@@ -2091,7 +2086,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
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),
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index cd0cdaa74..dc2c06701 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -104,7 +104,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
return this._activeAlignment;
}
@computed get textVcenter() {
- return BoolCast(this.layoutDoc?.layout_centered);
+ return BoolCast(this.layoutDoc?._layout_centered);
}
_disposer: IReactionDisposer | undefined;
componentDidMount() {
@@ -450,7 +450,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
vcenterToggle = (view: EditorView, dispatch: any) => {
- this.layoutDoc && (this.layoutDoc.layout_centered = !this.layoutDoc.layout_centered);
+ this.layoutDoc && (this.layoutDoc._layout_centered = !this.layoutDoc._layout_centered);
};
align = (view: EditorView, dispatch: any, alignment: 'left' | 'right' | 'center') => {
if (this.TextView?._props.rootSelected?.()) {
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 9bd41f42c..d5c91fc09 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -78,7 +78,7 @@ export class RichTextRules {
this.TextBox.dataDoc[paintedField] = CollectionView.LayoutString(this.TextBox.fieldKey);
const layoutFieldKey = StrCast(this.TextBox.layoutDoc.layout_fieldKey); // save the current layout fieldkey
this.TextBox.layoutDoc.layout_fieldKey = paintedField; // setup the paint layout field key
- this.TextBox.DocumentView?.().setToggleDetail(layoutFieldKey.replace('layout_', '').replace('layout', ''), 'onPaint'); // create the script to toggle between the painted and regular view
+ this.TextBox.DocumentView?.().setToggleDetail('onPaint'); // create the script to toggle between the painted and regular view
this.TextBox.layoutDoc.layout_fieldKey = layoutFieldKey; // restore the layout field key to text
return state.tr.delete(start, end).setBlockType(start, start, schema.nodes.code_block);