aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-04-19 11:02:05 -0400
committerbobzel <zzzman@gmail.com>2024-04-19 11:02:05 -0400
commitb6229b0a6141afbfd0e78e3ec870218187864def (patch)
tree26c6e752e4512abe42b92dcefd1a3b42df529494 /src
parent2a313f28fcb8675223708b0657de7517a3281095 (diff)
fixed text search highlighting. fixed first typed characfter of note to have marks.
Diffstat (limited to 'src')
-rw-r--r--src/client/apis/gpt/GPT.ts8
-rw-r--r--src/client/util/CurrentUserUtils.ts2
-rw-r--r--src/client/util/DropConverter.ts77
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx28
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx61
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.scss2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx346
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx2
-rw-r--r--src/client/views/nodes/formattedText/marks_rts.ts6
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx6
-rw-r--r--src/fields/Doc.ts160
-rw-r--r--src/fields/util.ts2
12 files changed, 397 insertions, 303 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 63563cb79..e3e87e017 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -27,9 +27,9 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
*/
let lastCall = '';
let lastResp = '';
-const gptAPICall = async (inputText: string, callType: GPTCallType) => {
- if (callType === GPTCallType.SUMMARY) inputText += '.';
- const opts: GPTCallOpts = callTypeMap[callType];
+const gptAPICall = async (inputTextIn: string, callType: GPTCallType) => {
+ const inputText = callType === GPTCallType.SUMMARY ? inputTextIn + '.' : inputTextIn;
+ const opts = callTypeMap[callType];
if (lastCall === inputText) return lastResp;
try {
const configuration: ClientOptions = {
@@ -69,8 +69,8 @@ const gptImageCall = async (prompt: string, n?: number) => {
// return response.data.data[0].url;
} catch (err) {
console.error(err);
- return;
}
+ return undefined;
};
export { gptAPICall, gptImageCall, GPTCallType };
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 7811f8605..535f7cf9d 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1057,4 +1057,4 @@ ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.import
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; });
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function getSharingDoc() { return Doc.SharingDoc() }); \ No newline at end of file
+ScriptingGlobals.add(function getSharingDoc() { return Doc.SharingDoc() });
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index ed5749d06..0314af06b 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -1,10 +1,9 @@
-import { Doc, DocListCast, Opt } from '../../fields/Doc';
+import { Doc, DocListCast, StrListCast } from '../../fields/Doc';
import { DocData } from '../../fields/DocSymbols';
import { ObjectField } from '../../fields/ObjectField';
import { RichTextField } from '../../fields/RichTextField';
-import { listSpec } from '../../fields/Schema';
import { ComputedField, ScriptField } from '../../fields/ScriptField';
-import { Cast, StrCast } from '../../fields/Types';
+import { StrCast } from '../../fields/Types';
import { ImageField } from '../../fields/URLField';
import { Docs } from '../documents/Documents';
import { DocumentType } from '../documents/DocumentTypes';
@@ -13,21 +12,6 @@ import { DragManager } from './DragManager';
import { ScriptingGlobals } from './ScriptingGlobals';
/**
- * Converts a Doc to a render template that can be applied to other Docs to customize how they render while
- * still using the other Doc as the backing data store (ie, dataDoc). During rendering, if a layout Doc is provided
- * with 'isTemplateDoc' set, then the layout Doc is treated as a template for the rendered Doc. The template Doc is
- * "expanded" to create an template instance for the rendered Doc.
- *
- *
- * @param doc the doc to convert to a template
- * @returns 'doc'
- */
-export function MakeTemplate(doc: Doc) {
- doc.isTemplateDoc = makeTemplate(doc, true);
- return doc;
-}
-
-/**
*
* Recursively converts 'doc' into a template that can be used to render other documents.
*
@@ -63,26 +47,22 @@ function makeTemplate(doc: Doc, first: boolean = true): boolean {
}
return isTemplate;
}
-export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
- data?.draggedDocuments.map((doc, i) => {
- let dbox = doc;
- // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
- if (doc.type === DocumentType.FONTICON || StrCast(Doc.Layout(doc).layout).includes(FontIconBox.name)) {
- if (data.dropPropertiesToRemove || dbox.dropPropertiesToRemove) {
- //dbox = Doc.MakeEmbedding(doc); // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon
- dbox = Doc.MakeEmbedding(dbox);
- const dragProps = Cast(dbox.dropPropertiesToRemove, listSpec('string'), []);
- const remProps = (data.dropPropertiesToRemove || []).concat(Array.from(dragProps));
- remProps.map(prop => (dbox[prop] = undefined));
- }
- } else if (!doc.onDragStart && !doc.isButtonBar) {
- dbox = makeUserTemplateButton(doc);
- } else if (doc.isButtonBar) {
- dbox.ignoreClick = true;
- }
- data.droppedDocuments[i] = dbox;
- });
+
+/**
+ * Converts a Doc to a render template that can be applied to other Docs to customize how they render while
+ * still using the other Doc as the backing data store (ie, dataDoc). During rendering, if a layout Doc is provided
+ * with 'isTemplateDoc' set, then the layout Doc is treated as a template for the rendered Doc. The template Doc is
+ * "expanded" to create an template instance for the rendered Doc.
+ *
+ *
+ * @param doc the doc to convert to a template
+ * @returns 'doc'
+ */
+export function MakeTemplate(doc: Doc) {
+ doc.isTemplateDoc = makeTemplate(doc, true);
+ return doc;
}
+
export function makeUserTemplateButton(doc: Doc) {
const layoutDoc = doc; // doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
if (layoutDoc.type !== DocumentType.FONTICON) {
@@ -106,7 +86,30 @@ export function makeUserTemplateButton(doc: Doc) {
dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory)');
return dbox;
}
+export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
+ data?.draggedDocuments.forEach((doc, i) => {
+ let dbox = doc;
+ // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
+ if (doc.type === DocumentType.FONTICON || StrCast(Doc.Layout(doc).layout).includes(FontIconBox.name)) {
+ if (data.dropPropertiesToRemove || dbox.dropPropertiesToRemove) {
+ // dbox = Doc.MakeEmbedding(doc); // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon
+ dbox = Doc.MakeEmbedding(dbox);
+ const dragProps = StrListCast(dbox.dropPropertiesToRemove);
+ const remProps = (data.dropPropertiesToRemove || []).concat(Array.from(dragProps));
+ remProps.forEach(prop => {
+ dbox[prop] = undefined;
+ });
+ }
+ } else if (!doc.onDragStart && !doc.isButtonBar) {
+ dbox = makeUserTemplateButton(doc);
+ } else if (doc.isButtonBar) {
+ dbox.ignoreClick = true;
+ }
+ data.droppedDocuments[i] = dbox;
+ });
+}
ScriptingGlobals.add(
+ // eslint-disable-next-line prefer-arrow-callback
function convertToButtons(dragData: any) {
convertDropDataToButtons(dragData as DragManager.DocumentDragData);
},
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 99f9c03bf..708536de0 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -52,13 +52,14 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
@undoBatch
private internalDrop = (e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
if (dropEvent.complete.docDragData) {
- const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments;
- const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.Document, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
- Doc.SetContainer(droppedDocs.lastElement(), this.dataDoc);
+ const { droppedDocuments } = dropEvent.complete.docDragData;
+ const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocuments, this.Document, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
+ Doc.SetContainer(droppedDocuments.lastElement(), this.dataDoc);
!added && e.preventDefault();
e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
return added;
}
+ return undefined;
};
private registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => {
@@ -83,7 +84,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
// on click, animate slider movement to the targetWidth
this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this._props.PanelWidth();
setTimeout(
- action(() => (this._animating = '')),
+ action(() => {
+ this._animating = '';
+ }),
200
);
})
@@ -109,7 +112,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
});
if (anchor) {
if (!addAsAnnotation) anchor.backgroundColor = 'transparent';
- /* addAsAnnotation &&*/ this.addDocument(anchor);
+ /* addAsAnnotation && */ this.addDocument(anchor);
PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), clippable: true } }, this.Document);
return anchor;
}
@@ -148,7 +151,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
return true;
},
emptyFunction,
- e => this.clearDoc(which)
+ () => this.clearDoc(which)
);
};
docStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
@@ -213,15 +216,16 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
const displayDoc = (whichSlot: string) => {
const whichDoc = DocCast(this.dataDoc[whichSlot]);
const targetDoc = DocCast(whichDoc?.annotationOn, whichDoc);
- const layoutTemplateString = targetDoc ? '' : this.testForTextFields(whichSlot);
- return targetDoc || layoutTemplateString ? (
+ const layoutString = targetDoc ? '' : this.testForTextFields(whichSlot);
+ return targetDoc || layoutString ? (
<>
<DocumentView
+ // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
- ignoreUsePath={layoutTemplateString ? true : undefined}
+ ignoreUsePath={layoutString ? true : undefined}
renderDepth={this.props.renderDepth + 1}
- LayoutTemplateString={layoutTemplateString}
- Document={layoutTemplateString ? this.Document : targetDoc}
+ LayoutTemplateString={layoutString}
+ Document={layoutString ? this.Document : targetDoc}
containerViewPath={this.DocumentView?.().docViewPath}
moveDocument={whichSlot.endsWith('1') ? this.moveDoc1 : this.moveDoc2}
removeDocument={whichSlot.endsWith('1') ? this.remDoc1 : this.remDoc2}
@@ -234,7 +238,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
hideLinkButton
pointerEvents={this._isAnyChildContentActive ? undefined : returnNone}
/>
- {layoutTemplateString ? null : clearButton(whichSlot)}
+ {layoutString ? null : clearButton(whichSlot)}
</> // placeholder image if doc is missing
) : (
<div className="placeholder">
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 74773b244..b8296ce51 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -1,3 +1,4 @@
+/* eslint-disable jsx-a11y/control-has-associated-label */
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@@ -79,7 +80,8 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
* @param value
* @returns
*/
- public static CompileKVPScript(rawvalue: string): KVPScript | undefined {
+ public static CompileKVPScript(rawvalueIn: string): KVPScript | undefined {
+ let rawvalue = rawvalueIn;
const onDelegate = rawvalue.startsWith('=');
rawvalue = onDelegate ? rawvalue.substring(1) : rawvalue;
const type: 'computed' | 'script' | false = rawvalue.startsWith(':=') ? 'computed' : rawvalue.startsWith('$=') ? 'script' : false;
@@ -87,7 +89,7 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
rawvalue = rawvalue.replace(/.*\(\((.*)\)\)/, 'dashCallChat(_setCacheResult_, this, `$1`)');
const value = ["'", '"', '`'].includes(rawvalue.length ? rawvalue[0] : '') || !isNaN(rawvalue as any) ? rawvalue : '`' + rawvalue + '`';
- var script = ScriptField.CompileScript(rawvalue, {}, true, undefined, DocumentIconContainer.getTransformer());
+ let script = ScriptField.CompileScript(rawvalue, {}, true, undefined, DocumentIconContainer.getTransformer());
if (!script.compiled) {
script = ScriptField.CompileScript(value, {}, true, undefined, DocumentIconContainer.getTransformer());
}
@@ -153,20 +155,20 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
const ids: { [key: string]: string } = {};
const protos = Doc.GetAllPrototypes(doc);
- for (const proto of protos) {
+ protos.forEach(proto => {
Object.keys(proto).forEach(key => {
if (!(key in ids) && realDoc[key] !== ComputedField.undefined) {
ids[key] = key;
}
});
- }
+ });
const rows: JSX.Element[] = [];
let i = 0;
const self = this;
const keys = Object.keys(ids).slice();
- //for (const key of [...keys.filter(id => id !== 'layout' && !id.includes('_')).sort(), ...keys.filter(id => id === 'layout' || id.includes('_')).sort()]) {
- for (const key of keys.sort((a: string, b: string) => {
+ // for (const key of [...keys.filter(id => id !== 'layout' && !id.includes('_')).sort(), ...keys.filter(id => id === 'layout' || id.includes('_')).sort()]) {
+ const sortedKeys = keys.sort((a: string, b: string) => {
const a_ = a.split('_')[0];
const b_ = b.split('_')[0];
if (a_ < b_) return -1;
@@ -174,7 +176,8 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
if (a === a_) return -1;
if (b === b_) return 1;
return a === b ? 0 : a < b ? -1 : 1;
- })) {
+ });
+ sortedKeys.forEach(key => {
rows.push(
<KeyValuePair
doc={realDoc}
@@ -195,7 +198,7 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
keyName={key}
/>
);
- }
+ });
return rows;
}
@computed get newKeyValue() {
@@ -229,7 +232,7 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
this._splitPercentage = Math.max(0, 100 - Math.round(((e.clientX - nativeWidth.left) / nativeWidth.width) * 100));
};
@action
- onDividerUp = (e: PointerEvent): void => {
+ onDividerUp = (): void => {
document.removeEventListener('pointermove', this.onDividerMove);
document.removeEventListener('pointerup', this.onDividerUp);
};
@@ -244,11 +247,11 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
const rows = this.rows.filter(row => row.isChecked);
if (rows.length > 1) {
const parent = Docs.Create.StackingDocument([], { _layout_autoHeight: true, _width: 300, title: `field views for ${DocCast(this._props.Document).title}`, _chromeHidden: true });
- for (const row of rows) {
+ rows.forEach(row => {
const field = this.createFieldView(DocCast(this._props.Document), row);
field && Doc.AddDocToList(parent, 'data', field);
row.uncheck();
- }
+ });
return parent;
}
return rows.length ? this.createFieldView(DocCast(this._props.Document), rows.lastElement()) : undefined;
@@ -256,22 +259,23 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
createFieldView = (templateDoc: Doc, row: KeyValuePair) => {
const metaKey = row._props.keyName;
- const fieldTemplate = Doc.IsDelegateField(templateDoc, metaKey) ? Doc.MakeDelegate(templateDoc) : Doc.MakeEmbedding(templateDoc);
- fieldTemplate.title = metaKey;
- fieldTemplate.layout_fitWidth = true;
- fieldTemplate._xMargin = 10;
- fieldTemplate._yMargin = 10;
- fieldTemplate._width = 100;
- fieldTemplate._height = 40;
- fieldTemplate.layout = this.inferType(templateDoc[metaKey], metaKey);
- return fieldTemplate;
+ const fieldTempDoc = Doc.IsDelegateField(templateDoc, metaKey) ? Doc.MakeDelegate(templateDoc) : Doc.MakeEmbedding(templateDoc);
+ fieldTempDoc.title = metaKey;
+ fieldTempDoc.layout_fitWidth = true;
+ fieldTempDoc._xMargin = 10;
+ fieldTempDoc._yMargin = 10;
+ fieldTempDoc._width = 100;
+ fieldTempDoc._height = 40;
+ fieldTempDoc.layout = this.inferType(templateDoc[metaKey], metaKey);
+ return fieldTempDoc;
};
inferType = (data: FieldResult, metaKey: string) => {
const options = { _width: 300, _height: 300, title: metaKey };
if (data instanceof RichTextField || typeof data === 'string' || typeof data === 'number') {
return FormattedTextBox.LayoutString(metaKey);
- } else if (data instanceof List) {
+ }
+ if (data instanceof List) {
if (data.length === 0) {
return Docs.Create.StackingDocument([], options);
}
@@ -280,21 +284,18 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
return Docs.Create.StackingDocument([], options);
}
switch (first.data.constructor) {
- case RichTextField:
- return Docs.Create.TreeDocument([], options);
- case ImageField:
- return Docs.Create.MasonryDocument([], options);
- default:
- console.log(`Template for ${first.data.constructor} not supported!`);
- return undefined;
- }
+ case RichTextField: return Docs.Create.TreeDocument([], options);
+ case ImageField: return Docs.Create.MasonryDocument([], options);
+ default: console.log(`Template for ${first.data.constructor} not supported!`);
+ return undefined;
+ } // prettier-ignore
} else if (data instanceof ImageField) {
return ImageBox.LayoutString(metaKey);
}
return new Doc();
};
- specificContextMenu = (e: React.MouseEvent): void => {
+ specificContextMenu = (): void => {
const cm = ContextMenu.Instance;
const open = cm.findByDescription('Change Perspective...');
const openItems: ContextMenuProps[] = open && 'subitems' in open ? open.subitems : [];
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index 38dd2e847..5b2b558fc 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -350,7 +350,7 @@ footnote::before {
span {
font-family: inherit;
background-color: inherit;
- display: contents; // fixes problem where extra space is added around <ol> lists when inside a prosemirror span
+ display: inline; // needs to be inline for search highlighting to appear // contents; // fixes problem where extra space is added around <ol> lists when inside a prosemirror span
}
blockquote {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 31252e0ab..c7543560d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -13,7 +13,7 @@ import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from '
import { EditorView } from 'prosemirror-view';
import * as React from 'react';
import { BsMarkdownFill } from 'react-icons/bs';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, DivWidth, returnFalse, returnZero, setupMoveUpEvents, smoothScroll } from '../../../../ClientUtils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, DivWidth, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, StopEvent } from '../../../../ClientUtils';
import { DateField } from '../../../../fields/DateField';
import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc';
import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, DocData, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols';
@@ -82,6 +82,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return FieldView.LayoutString(FormattedTextBox, fieldStr);
}
public static blankState = () => EditorState.create(FormattedTextBox.Instance.config);
+ // eslint-disable-next-line no-use-before-define
public static Instance: FormattedTextBox;
public static LiveTextUndo: UndoManager.Batch | undefined;
static _globalHighlightsCache: string = '';
@@ -100,7 +101,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
private _inDrop = false;
private _finishingLink = false;
private _searchIndex = 0;
- private _lastTimedMark: Mark | undefined = undefined;
private _cachedLinks: Doc[] = [];
private _undoTyping?: UndoManager.Batch;
private _disposers: { [name: string]: IReactionDisposer } = {};
@@ -111,10 +111,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
private _keymap: any = undefined;
private _rules: RichTextRules | undefined;
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 _forceDownNode: Node | undefined;
- private _downX = 0;
- private _downY = 0;
- private _downTime = 0;
private _break = true;
public ProseRef?: HTMLDivElement;
public get EditorView() {
@@ -173,8 +169,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
keymap(baseKeymap),
new Plugin({ props: { attributes: { class: 'ProseMirror-example-setup-style' } } }),
new Plugin({
- view(editorView) {
- return new FormattedTextBoxComment(editorView);
+ view(/* editorView */) {
+ return new FormattedTextBoxComment();
},
}),
],
@@ -220,13 +216,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
public RemoveLinkFromDoc(linkDoc?: Doc) {
this.unhighlightSearchTerms();
const state = this._editorView?.state;
- const a1 = linkDoc?.link_anchor_1 as Doc;
- const a2 = linkDoc?.link_anchor_2 as Doc;
+ const a1 = DocCast(linkDoc?.link_anchor_1);
+ const a2 = DocCast(linkDoc?.link_anchor_2);
if (state && a1 && a2 && this._editorView) {
this.removeDocument(a1);
this.removeDocument(a2);
- var allFoundLinkAnchors: any[] = [];
- state.doc.nodesBetween(0, state.doc.nodeSize - 2, (node: any, pos: number, parent: any) => {
+ let allFoundLinkAnchors: any[] = [];
+ state.doc.nodesBetween(0, state.doc.nodeSize - 2, (node: any /* , pos: number, parent: any */) => {
const foundLinkAnchors = findLinkMark(node.marks)?.attrs.allAnchors.filter((a: any) => a.anchorId === a1[Id] || a.anchorId === a2[Id]) || [];
allFoundLinkAnchors = foundLinkAnchors.length ? foundLinkAnchors : allFoundLinkAnchors;
return true;
@@ -249,7 +245,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
- const rootDoc = Doc.isTemplateDoc(this._props.docViewPath().lastElement()?.Document) ? this.Document : DocCast(this.Document.rootDocument, this.Document);
+ const rootDoc: Doc = 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);
@@ -264,11 +260,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
setupAnchorMenu = () => {
AnchorMenu.Instance.Status = 'marquee';
- AnchorMenu.Instance.OnClick = (e: PointerEvent) => {
+ AnchorMenu.Instance.OnClick = () => {
!this.layoutDoc.layout_showSidebar && this.toggleSidebar();
setTimeout(() => this._sidebarRef.current?.anchorMenuClick(this.makeLinkAnchor(undefined, OpenWhere.addRight, undefined, 'Anchored Selection', true))); // give time for sidebarRef to be created
};
- AnchorMenu.Instance.OnAudio = (e: PointerEvent) => {
+ AnchorMenu.Instance.OnAudio = () => {
!this.layoutDoc.layout_showSidebar && this.toggleSidebar();
const anchor = this.makeLinkAnchor(undefined, OpenWhere.addRight, undefined, 'Anchored Selection', true, true);
@@ -279,7 +275,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
let stopFunc: any;
const targetData = target[DocData];
targetData.mediaState = mediaState.Recording;
- DocumentViewInternal.recordAudioAnnotation(targetData, Doc.LayoutFieldKey(target), stop => (stopFunc = stop));
+ DocumentViewInternal.recordAudioAnnotation(targetData, Doc.LayoutFieldKey(target), stop => { stopFunc = stop }); // prettier-ignore
+
const reactionDisposer = reaction(
() => target.mediaState,
dictation => {
@@ -324,7 +321,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
ele.append(contents);
}
this._selectionHTML = ele?.innerHTML;
- } catch (e) {}
+ } catch (e) {
+ /* empty */
+ }
};
leafText = (node: Node) => {
@@ -339,7 +338,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return '';
};
dispatchTransaction = (tx: Transaction) => {
- if (this._editorView && (this._editorView as any).docView) {
+ if (this._editorView) {
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
this.tryUpdateDoc(false);
@@ -347,13 +346,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
tryUpdateDoc = (force: boolean) => {
- if (this._editorView && (this._editorView as any).docView) {
+ if (this._editorView) {
const { state } = this._editorView;
const { dataDoc } = this;
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);
@@ -362,7 +360,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if ([AclEdit, AclAdmin, AclSelfEdit, AclAugment].includes(effectiveAcl)) {
const accumTags = [] as string[];
- state.tr.doc.nodesBetween(0, state.doc.content.size, (node: any, pos: number, parent: any) => {
+ state.tr.doc.nodesBetween(0, state.doc.content.size, (node: any /* , pos: number, parent: any */) => {
if (node.type === schema.nodes.dashField && node.attrs.fieldKey.startsWith('#')) {
accumTags.push(node.attrs.fieldKey);
}
@@ -417,37 +415,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
insertTime = () => {
let linkTime;
let linkAnchor;
- let link;
- LinkManager.Links(this.dataDoc).forEach((l, i) => {
- const anchor = (l.link_anchor_1 as Doc).annotationOn ? (l.link_anchor_1 as Doc) : (l.link_anchor_2 as Doc).annotationOn ? (l.link_anchor_2 as Doc) : undefined;
+ LinkManager.Links(this.dataDoc).forEach(l => {
+ const anchor = DocCast(l.link_anchor_1)?.annotationOn ? DocCast(l.link_anchor_1) : DocCast(l.link_anchor_2)?.annotationOn ? DocCast(l.link_anchor_2) : undefined;
if (anchor && (anchor.annotationOn as Doc).mediaState === mediaState.Recording) {
linkTime = NumCast(anchor._timecodeToShow /* audioStart */);
linkAnchor = anchor;
- link = l;
}
});
if (this._editorView && linkTime) {
- const state = this._editorView.state;
- const now = Date.now();
- let mark = schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail, modified: Math.floor(now / 1000) });
- if (!this._break && state.selection.to !== state.selection.from) {
- for (let i = state.selection.from; i <= state.selection.to; i++) {
- const pos = state.doc.resolve(i);
- const um = Array.from(pos.marks()).find(m => m.type === schema.marks.user_mark);
- if (um) {
- mark = um;
- break;
- }
- }
- }
-
- const path = (this._editorView.state.selection.$from as any).path;
- if (linkAnchor && path[path.length - 3].type !== this._editorView.state.schema.nodes.code_block) {
+ const { state } = this._editorView;
+ const { path } = state.selection.$from as any;
+ if (linkAnchor && path[path.length - 3].type !== state.schema.nodes.code_block) {
const time = linkTime + Date.now() / 1000 - this._recordingStart / 1000;
this._break = false;
- const from = state.selection.from;
- const value = this._editorView.state.schema.nodes.audiotag.create({ timeCode: time, audioId: linkAnchor[Id] });
- const replaced = this._editorView.state.tr.insert(from - 1, value);
+ const { from } = state.selection;
+ const value = state.schema.nodes.audiotag.create({ timeCode: time, audioId: linkAnchor[Id] });
+ const replaced = state.tr.insert(from - 1, value);
this._editorView.dispatch(replaced.setSelection(new TextSelection(replaced.doc.resolve(from + 1))));
}
}
@@ -464,14 +447,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
link.link_relationship === LinkManager.AutoKeywords
); // prettier-ignore
if (this._editorView?.state.doc.textContent) {
- 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.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)));
+ let { tr } = this._editorView.state;
+ const { from, to } = this._editorView.state.selection;
+ const { autoLinkAnchor } = this._editorView.state.schema.marks;
+ tr = tr.removeMark(0, tr.doc.content.size, autoLinkAnchor);
+ Doc.MyPublishedDocs.filter(term => term.title).forEach(term => {
+ tr = this.hyperlinkTerm(tr, term, newAutoLinks);
+ });
+ tr = tr.setSelection(new TextSelection(tr.doc.resolve(from), tr.doc.resolve(to)));
this._editorView?.dispatch(tr);
}
oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.link_anchor_2 !== this.Document).forEach(LinkManager.Instance.deleteLink);
@@ -507,11 +490,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
* function of a freeform view that is driven by the text box's text. The include directive will copy the code of the published
* document into the code being evaluated.
*/
- hyperlinkTerm = (tr: any, target: Doc, newAutoLinks: Set<Doc>) => {
+ hyperlinkTerm = (trIn: any, target: Doc, newAutoLinks: Set<Doc>) => {
+ let tr = trIn;
const editorView = this._editorView;
- if (editorView && (editorView as any).docView && !Doc.AreProtosEqual(target, this.Document)) {
+ if (editorView && !Doc.AreProtosEqual(target, this.Document)) {
const autoLinkTerm = Field.toString(target.title as FieldType).replace(/^@/, '');
- var alink: Doc | undefined;
+ let alink: Doc | undefined;
this.findInNode(editorView, editorView.state.doc, autoLinkTerm).forEach(sel => {
if (
!sel.$anchor.pos ||
@@ -523,7 +507,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
) {
const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() });
tr = tr.addMark(sel.from, sel.to, splitter);
- tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => {
+ tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number /* , parent: any */) => {
if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
alink =
alink ??
@@ -554,12 +538,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return true;
};
highlightSearchTerms = (terms: string[], backward: boolean) => {
- if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
- const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
- const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
- const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
- const length = res[0].length;
- let tr = this._editorView.state.tr;
+ const { _editorView } = this;
+ if (_editorView && terms.some(t => t)) {
+ const { state } = _editorView;
+ let { tr } = state;
+ const mark = state.schema.mark(state.schema.marks.search_highlight);
+ const activeMark = state.schema.mark(state.schema.marks.search_highlight, { selected: true });
+ const res = terms.filter(t => t).map(term => this.findInNode(_editorView, state.doc, term));
+ const { length } = res[0];
const flattened: TextSelection[] = [];
res.map(r => r.map(h => flattened.push(h)));
this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
@@ -574,18 +560,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
const lastSel = Math.min(flattened.length - 1, this._searchIndex);
- flattened.forEach((h: TextSelection, ind: number) => (tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark)));
- flattened[lastSel] && this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
+ flattened.forEach((h: TextSelection, ind: number) => {
+ tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark);
+ });
+ flattened[lastSel] && _editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
}
};
unhighlightSearchTerms = () => {
- if (window.screen.width < 600) null;
- else if (this._editorView && (this._editorView as any).docView) {
- const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
- const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
- const end = this._editorView.state.doc.nodeSize - 2;
- this._editorView.dispatch(this._editorView.state.tr.removeMark(0, end, mark).removeMark(0, end, activeMark));
+ if (this._editorView) {
+ const { state } = this._editorView;
+ if (state) {
+ const mark = state.schema.mark(state.schema.marks.search_highlight);
+ const activeMark = state.schema.mark(state.schema.marks.search_highlight, { selected: true });
+ const end = state.doc.nodeSize - 2;
+ this._editorView.dispatch(state.tr.removeMark(0, end, mark).removeMark(0, end, activeMark));
+ }
}
};
adoptAnnotation = (start: number, end: number, mark: Mark) => {
@@ -634,7 +624,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
float: 'unset',
});
if (!de.embedKey && ![dropActionType.embed, dropActionType.copy].includes(dropAction ?? dropActionType.move)) {
- added = dragData.removeDocument?.(draggedDoc) ? true : false;
+ added = !!dragData.removeDocument?.(draggedDoc);
} else {
added = true;
}
@@ -646,7 +636,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
this._inDrop = true;
const pos = view.posAtCoords({ left: de.x, top: de.y })?.pos;
pos && view.dispatch(view.state.tr.insert(pos, node));
- added = pos ? true : false; // pos will be null if you don't drop onto an actual text location
+ added = !!pos; // pos will be null if you don't drop onto an actual text location
} catch (e) {
console.log('Drop failed', e);
added = false;
@@ -680,29 +670,28 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
offset += (context.content as any).content[i].nodeSize;
}
- return null;
- } else {
- return null;
}
+ return null;
}
- //Recursively finds matches within a given node
+ // Recursively finds matches within a given node
findInNode(pm: EditorView, node: Node, find: string) {
let ret: TextSelection[] = [];
if (node.isTextblock) {
- let index = 0,
- foundAt;
+ let index = 0;
+ let foundAt;
const ep = this.getNodeEndpoints(pm.state.doc, node);
const regexp = new RegExp(find, 'i');
if (regexp) {
- var blockOffset = 0;
- for (var i = 0; i < node.childCount; i++) {
- var textContent = '';
+ let blockOffset = 0;
+ for (let i = 0; i < node.childCount; i++) {
+ let textContent = '';
while (i < node.childCount && node.child(i).type === pm.state.schema.nodes.text) {
textContent += node.child(i).textContent;
i++;
}
+ // eslint-disable-next-line no-cond-assign
while (ep && (foundAt = textContent.slice(index).search(regexp)) > -1) {
const sel = new TextSelection(pm.state.doc.resolve(ep.from + index + blockOffset + foundAt + 1), pm.state.doc.resolve(ep.from + index + blockOffset + foundAt + find.length + 1));
ret.push(sel);
@@ -713,14 +702,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
}
} else {
- node.content.forEach((child, i) => (ret = ret.concat(this.findInNode(pm, child, find))));
+ node.content.forEach(child => {
+ ret = ret.concat(this.findInNode(pm, child, find));
+ });
}
return ret;
}
updateHighlights = (highlights: string[]) => {
if (Array.from(highlights).join('') === FormattedTextBox._globalHighlightsCache) return;
- setTimeout(() => (FormattedTextBox._globalHighlightsCache = Array.from(highlights).join('')));
+ setTimeout(() => {
+ FormattedTextBox._globalHighlightsCache = Array.from(highlights).join('');
+ });
clearStyleSheetRules(FormattedTextBox._userStyleSheet);
if (!highlights.includes('Audio Tags')) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'audiotag', { display: 'none' }, '');
@@ -757,12 +750,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
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() }));
}
+ // eslint-disable-next-line operator-assignment
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;
@computed get SidebarShown() {
- return this._showSidebar || this.layoutDoc._layout_showSidebar ? true : false;
+ return !!(this._showSidebar || this.layoutDoc._layout_showSidebar);
}
@action
@@ -820,7 +814,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
pinToPres = (anchor: Doc) => this._props.pinToPres(anchor, {});
@undoBatch
- makeTargetToggle = (anchor: Doc) => (anchor.followLinkToggle = !anchor.followLinkToggle);
+ makeTargetToggle = (anchor: Doc) => {
+ anchor.followLinkToggle = !anchor.followLinkToggle;
+ };
@undoBatch
showTargetTrail = (anchor: Doc) => {
@@ -836,11 +832,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
specificContextMenu = (e: React.MouseEvent): void => {
const cm = ContextMenu.Instance;
- const editor = this._editorView!;
- const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
let target = e.target as any; // hrefs are stored on the database of the <a> node that wraps the hyerlink <span>
while (target && !target.dataset?.targethrefs) target = target.parentElement;
- if (target && !(e.nativeEvent as any).dash) {
+ const editor = this._editorView;
+ if (editor && target && !(e.nativeEvent as any).dash) {
const hrefs = (target.dataset?.targethrefs as string)
?.trim()
.split(' ')
@@ -850,8 +845,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
.replace(Doc.localServerPath(), '')
.split('?')[0];
const deleteMarkups = undoBatch(() => {
- const sel = editor.state.selection;
- editor.dispatch(editor.state.tr.removeMark(sel.from, sel.to, editor.state.schema.marks.linkAnchor));
+ const { selection } = editor.state;
+ editor.dispatch(editor.state.tr.removeMark(selection.from, selection.to, editor.state.schema.marks.linkAnchor));
});
e.persist();
anchorDoc &&
@@ -887,7 +882,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
event: undoBatch(() => {
this.dataDoc.layout_meta = Cast(Doc.UserDoc().emptyHeader, Doc, null)?.layout;
this.Document.layout_fieldKey = 'layout_meta';
- setTimeout(() => (this.layoutDoc._header_height = this.layoutDoc._layout_autoHeightMargins = 50), 50);
+ setTimeout(() => {
+ this.layoutDoc._header_height = this.layoutDoc._layout_autoHeightMargins = 50;
+ }, 50);
}),
icon: 'eye',
});
@@ -926,19 +923,26 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
appearanceItems.push({
description: !this.Document._layout_noSidebar ? 'Hide Sidebar Handle' : 'Show Sidebar Handle',
- event: () => (this.layoutDoc._layout_noSidebar = !this.layoutDoc._layout_noSidebar),
+ event: () => {
+ this.layoutDoc._layout_noSidebar = !this.layoutDoc._layout_noSidebar;
+ },
icon: !this.Document._layout_noSidebar ? 'eye-slash' : 'eye',
});
appearanceItems.push({
description: (this.Document._layout_enableAltContentUI ? 'Hide' : 'Show') + ' Alt Content UI',
- event: () => (this.layoutDoc._layout_enableAltContentUI = !this.layoutDoc._layout_enableAltContentUI),
+ event: () => {
+ this.layoutDoc._layout_enableAltContentUI = !this.layoutDoc._layout_enableAltContentUI;
+ },
icon: !this.Document._layout_enableAltContentUI ? 'eye-slash' : 'eye',
});
!Doc.noviceMode && appearanceItems.push({ description: 'Show Highlights...', noexpand: true, subitems: highlighting, icon: 'hand-point-right' });
!Doc.noviceMode &&
appearanceItems.push({
description: 'Broadcast Message',
- event: () => DocServer.GetRefField('rtfProto').then(proto => proto instanceof Doc && (proto.BROADCAST_MESSAGE = Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text)),
+ event: () =>
+ DocServer.GetRefField('rtfProto').then(proto => {
+ proto instanceof Doc && (proto.BROADCAST_MESSAGE = Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text);
+ }),
icon: 'expand-arrows-alt',
});
@@ -960,19 +964,29 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
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: `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 &&
optionItems.push({
description: !this.Document._createDocOnCR ? 'Create New Doc on Carriage Return' : 'Allow Carriage Returns',
- event: () => (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR),
+ event: () => {
+ this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR;
+ },
icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars',
});
!Doc.noviceMode &&
optionItems.push({
description: `${this.Document._layout_autoHeight ? 'Lock' : 'Auto'} Height`,
- event: () => (this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight),
+ event: () => {
+ this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight;
+ },
icon: this.Document._layout_autoHeight ? 'lock' : 'unlock',
});
!options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'eye' });
@@ -980,7 +994,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
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;
};
animateRes = (resIndex: number, newText: string) => {
@@ -995,7 +1008,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
askGPT = action(async () => {
try {
- let res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION);
+ const res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION);
if (!res) {
console.error('GPT call failed');
this.animateRes(0, 'Something went wrong.');
@@ -1020,8 +1033,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (this._editorView && this._recordingDictation) {
this.stopDictation(true);
this._break = true;
- const state = this._editorView.state;
- const to = state.selection.to;
+ const { state } = this._editorView;
+ const { to } = state.selection;
const updated = TextSelection.create(state.doc, to, to);
this._editorView.dispatch(state.tr.setSelection(updated).insert(to, state.schema.nodes.paragraph.create({})));
if (this._recordingDictation) {
@@ -1067,7 +1080,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
}
}
- const from = this._editorView.state.selection.from;
+ const { from } = this._editorView.state.selection;
this._break = false;
const tr = this._editorView.state.tr.insertText(value);
this._editorView.dispatch(tr.setSelection(TextSelection.create(tr.doc, from, tr.doc.content.size)).scrollIntoView());
@@ -1076,23 +1089,24 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
// TODO: nda -- Look at how link anchors are added
makeLinkAnchor(anchorDoc?: Doc, location?: string, targetHref?: string, title?: string, noPreview?: boolean, addAsAnnotation?: boolean) {
- const state = this._editorView?.state;
- if (state) {
+ const { _editorView } = this;
+ if (_editorView) {
+ const { state } = _editorView;
let selectedText = '';
- const sel = state.selection;
+ const { selection } = state;
const splitter = state.schema.marks.splitter.create({ id: Utils.GenerateGuid() });
- let tr = state.tr.addMark(sel.from, sel.to, splitter);
- if (sel.from !== sel.to) {
+ let tr = state.tr.addMark(selection.from, selection.to, splitter);
+ if (selection.from !== selection.to) {
const anchor =
anchorDoc ??
Docs.Create.ConfigDocument({
//
- title: 'text(' + this._editorView?.state.doc.textBetween(sel.from, sel.to) + ')',
+ title: 'text(' + state.doc.textBetween(selection.from, selection.to) + ')',
annotationOn: this.dataDoc,
});
const href = targetHref ?? Doc.localServerPath(anchor);
if (anchor !== anchorDoc && addAsAnnotation) this.addDocument(anchor);
- tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => {
+ tr.doc.nodesBetween(selection.from, selection.to, (node: any, pos: number /* , parent: any */) => {
if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
const allAnchors = [{ href, title, anchorId: anchor[Id] }];
allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.linkAnchor.name)?.attrs.allAnchors ?? []));
@@ -1102,7 +1116,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
});
this.dataDoc[ForceServerWrite] = this.dataDoc[UpdatingFromServer] = true; // need to allow permissions for adding links to readonly/augment only documents
- this._editorView!.dispatch(tr.removeMark(sel.from, sel.to, splitter));
+ this._editorView!.dispatch(tr.removeMark(selection.from, selection.to, splitter));
this.dataDoc[UpdatingFromServer] = this.dataDoc[ForceServerWrite] = false;
anchor.text = selectedText;
anchor.text_html = this._selectionHTML ?? selectedText;
@@ -1123,15 +1137,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
setTimeout(() => this._sidebarRef?.current?.makeDocUnfiltered(doc));
}
- return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
+ return new Promise<Opt<DocumentView>>(res => {
+ DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv));
+ });
};
focus = (textAnchor: Doc, options: FocusViewOptions) => {
const focusSpeed = options.zoomTime ?? 500;
const textAnchorId = textAnchor[Id];
+ let start = 0;
const findAnchorFrag = (frag: Fragment, editor: EditorView) => {
const nodes: Node[] = [];
let hadStart = start !== 0;
frag.forEach((node, index) => {
+ // eslint-disable-next-line no-use-before-define
const examinedNode = findAnchorNode(node, editor);
if (examinedNode?.node && (examinedNode.node.textContent || examinedNode.node.type === this._editorView?.state.schema.nodes.dashDoc || examinedNode.node.type === this._editorView?.state.schema.nodes.audiotag)) {
nodes.push(examinedNode.node);
@@ -1163,7 +1181,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return linkIndex !== -1 && marks[linkIndex].attrs.allAnchors.find((item: { href: string }) => textAnchorId === item.href.replace(/.*\/doc\//, '')) ? { node, start: 0 } : undefined;
};
- let start = 0;
this._didScroll = false; // assume we don't need to scroll. if we do, this will get set to true in handleScrollToSelextion when we dispatch the setSelection below
if (this._editorView && textAnchorId) {
const editor = this._editorView;
@@ -1179,13 +1196,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView());
const escAnchorId = textAnchorId[0] >= '0' && textAnchorId[0] <= '9' ? `\\3${textAnchorId[0]} ${textAnchorId.substr(1)}` : textAnchorId;
addStyleSheetRule(FormattedTextBox._highlightStyleSheet, `${escAnchorId}`, { background: 'yellow', transform: 'scale(3)', 'transform-origin': 'left bottom' });
- setTimeout(() => (this._focusSpeed = undefined), this._focusSpeed);
+ setTimeout(() => {
+ this._focusSpeed = undefined;
+ }, this._focusSpeed);
setTimeout(() => clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this._focusSpeed || 0, 3000));
return focusSpeed;
- } else {
- return this._props.focus(this.Document, options);
}
+ return this._props.focus(this.Document, options);
}
+ return undefined;
};
// if the scroll height has changed and we're in layout_autoHeight mode, then we need to update the textHeight component of the doc.
@@ -1205,7 +1224,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
this._disposers.breakupDictation = reaction(() => Doc.RecordingEvent, this.breakupDictation);
this._disposers.layout_autoHeight = reaction(
() => ({ autoHeight: this.layout_autoHeight, fontSize: this.fontSize, css: this.Document[DocCss] }),
- (autoHeight, fontSize) => setTimeout(() => autoHeight && this.tryUpdateScrollHeight())
+ autoHeight => setTimeout(() => autoHeight && this.tryUpdateScrollHeight())
);
this._disposers.highlights = reaction(
() => Array.from(FormattedTextBox._globalHighlights).slice(),
@@ -1214,7 +1233,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
);
this._disposers.width = reaction(
() => this._props.PanelWidth(),
- width => this.tryUpdateScrollHeight()
+ () => this.tryUpdateScrollHeight()
);
this._disposers.scrollHeight = reaction(
() => ({ scrollHeight: this.scrollHeight, layoutAutoHeight: this.layout_autoHeight, width: NumCast(this.layoutDoc._width) }),
@@ -1348,7 +1367,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return text;
};
- handlePaste = (view: EditorView, event: Event, slice: Slice): boolean => {
+ handlePaste = (view: EditorView, event: Event /* , slice: Slice */): boolean => {
const pdfAnchorId = (event as ClipboardEvent).clipboardData?.getData('dash/pdfAnchor');
return !!(pdfAnchorId && this.addPdfReference(pdfAnchorId));
};
@@ -1381,7 +1400,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return false;
};
- isActiveTab(el: Element | null | undefined) {
+ isActiveTab(elIn: Element | null | undefined) {
+ let el = elIn;
while (el && el !== document.body) {
if (getComputedStyle(el).display === 'none') return false;
el = el.parentNode as any;
@@ -1477,9 +1497,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const tr = tr2.setStoredMarks(storedMarks);
this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
+ this.tryUpdateDoc(true); // calling select() above will make isContentActive() true only after a render .. which means the selectAll() above won't write to the Document and the incomingValue will overwrite the selection with the non-updated data
} else if (curText && !FormattedTextBox.DontSelectInitialText) {
selectAll(this._editorView.state, this._editorView?.dispatch);
this.tryUpdateDoc(true); // calling select() above will make isContentActive() true only after a render .. which means the selectAll() above won't write to the Document and the incomingValue will overwrite the selection with the non-updated data
+ } else {
+ 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: ClientUtils.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;
+ this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))).setStoredMarks(storedMarks));
+ this.tryUpdateDoc(true); // calling select() above will make isContentActive() true only after a render .. which means the selectAll() above won't write to the Document and the incomingValue will overwrite the selection with the non-updated data
}
}
if (selectOnLoad) {
@@ -1526,8 +1555,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
onPointerDown = (e: React.PointerEvent): void => {
if ((e.nativeEvent as any).handledByInnerReactInstance) {
- return; //e.stopPropagation();
- } else (e.nativeEvent as any).handledByInnerReactInstance = true;
+ return; // e.stopPropagation();
+ }
+ (e.nativeEvent as any).handledByInnerReactInstance = true;
if (this.Document.forceActive) e.stopPropagation();
this.tryUpdateScrollHeight(); // if a doc a fitWidth doc is being viewed in different embedContainer (eg freeform & lightbox), then it will have conflicting heights. so when the doc is clicked on, we want to make sure it has the appropriate height for the selected view.
@@ -1553,9 +1583,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (this._recordingDictation && !e.ctrlKey && e.button === 0) {
this.breakupDictation();
}
- this._downX = e.clientX;
- this._downY = e.clientY;
- this._downTime = Date.now();
FormattedTextBoxComment.textBox = this;
if (e.button === 0 && this._props.rootSelected?.() && !e.altKey && !e.ctrlKey && !e.metaKey) {
if (e.clientX < this.ProseRef!.getBoundingClientRect().right) {
@@ -1569,9 +1596,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
e.preventDefault();
}
};
- onSelectEnd = (e: PointerEvent) => {
- document.removeEventListener('pointerup', this.onSelectEnd);
- };
+ onSelectEnd = (): void => document.removeEventListener('pointerup', this.onSelectEnd);
onPointerUp = (e: React.PointerEvent): void => {
const state = this.EditorView?.state;
if (state && this.ProseRef?.children[0].className.includes('-focused') && this._props.isContentActive() && !e.button) {
@@ -1607,7 +1632,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
@action
onFocused = (e: React.FocusEvent): void => {
- //applyDevTools.applyDevTools(this._editorView);
+ // applyDevTools.applyDevTools(this._editorView);
this.ProseRef?.children[0] === e.nativeEvent.target && this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this._props, this.layoutDoc);
e.stopPropagation();
};
@@ -1618,10 +1643,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
e.stopPropagation();
return;
}
- if (Math.abs(e.clientX - this._downX) > 4 || Math.abs(e.clientY - this._downY) > 4) {
- this._forceDownNode = undefined;
- return;
- }
if (!this._forceUncollapse || (this._editorView!.root as any).getSelection().isCollapsed) {
// this is a hack to allow the cursor to be placed at the end of a document when the document ends in an inline dash comment. Apparently Chrome on Windows has a bug/feature which breaks this when clicking after the end of the text.
const pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY });
@@ -1645,13 +1666,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (this._props.rootSelected?.()) {
// if text box is selected, then it consumes all click events
(e.nativeEvent as any).handledByInnerReactInstance = true;
- this.hitBulletTargets(e.clientX, e.clientY, !this._editorView?.state.selection.empty || this._forceUncollapse, false, this._forceDownNode, e.shiftKey);
+ this.hitBulletTargets(e.clientX, e.clientY, !this._editorView?.state.selection.empty || this._forceUncollapse, false, e.shiftKey);
}
this._forceUncollapse = !(this._editorView!.root as any).getSelection().isCollapsed;
- this._forceDownNode = (this._editorView!.state.selection as NodeSelection)?.node;
};
// this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them.
- hitBulletTargets(x: number, y: number, collapse: boolean, highlightOnly: boolean, downNode: Node | undefined = undefined, selectOrderedList: boolean = false) {
+ hitBulletTargets(x: number, y: number, collapse: boolean, highlightOnly: boolean, selectOrderedList: boolean = false) {
this._forceUncollapse = false;
clearStyleSheetRules(FormattedTextBox._bulletStyleSheet);
const clickPos = this._editorView!.posAtCoords({ left: x, top: y });
@@ -1721,6 +1741,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
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;
+ // eslint-disable-next-line prefer-destructuring
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));
}
@@ -1730,31 +1751,29 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
FormattedTextBox.LiveTextUndo?.end();
FormattedTextBox.LiveTextUndo = undefined;
- const state = this._editorView!.state;
// 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) => {
+ const { _editorView } = this;
+ if (!_editorView) return;
if ((e.altKey || e.ctrlKey) && e.key === 't') {
- e.preventDefault();
- e.stopPropagation();
this._props.setTitleFocus?.();
+ StopEvent(e);
return;
}
- const state = this._editorView!.state;
+ const { state } = _editorView;
if (!state.selection.empty && e.key === '%') {
this._rules!.EnteringStyle = true;
- e.preventDefault();
- e.stopPropagation();
+ StopEvent(e);
return;
}
if (state.selection.empty || !this._rules!.EnteringStyle) {
this._rules!.EnteringStyle = false;
}
- let stopPropagation = true;
- for (var i = state.selection.from; i <= state.selection.to; i++) {
+ for (let i = state.selection.from; i <= state.selection.to; i++) {
const node = state.doc.resolve(i);
if (state.doc.content.size - 1 > i && node?.marks?.().some(mark => mark.type === schema.marks.user_mark && mark.attrs.userid !== ClientUtils.CurrentUserEmail) && [AclAugment, AclSelfEdit].includes(GetEffectiveAcl(this.Document))) {
e.preventDefault();
@@ -1769,22 +1788,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return;
case 'Enter':
this.insertTime();
+ // eslint-disable-next-line no-fallthrough
case 'Tab':
e.preventDefault();
break;
- case 'c':
- this._editorView?.state.selection.empty && (stopPropagation = false);
+ case 'Space':
+ case 'Backspace':
break;
default:
- if (this._lastTimedMark?.attrs.userid === ClientUtils.CurrentUserEmail) break;
- case ' ':
- 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: ClientUtils.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })));
+ if ([AclEdit, AclAugment, AclAdmin].includes(GetEffectiveAcl(this.Document))) {
+ const modified = Math.floor(Date.now() / 1000);
+ const mark = state.selection.$to.marks().find(m => m.type === schema.marks.user_mark && m.attrs.modified === modified);
+ _editorView.dispatch(state.tr.removeStoredMark(schema.marks.user_mark).addStoredMark(mark ?? schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail, modified })));
}
break;
}
- if (stopPropagation) e.stopPropagation();
+ e.stopPropagation();
this.startUndoTypingBatch();
};
ondrop = (e: React.DragEvent) => {
@@ -1804,6 +1823,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
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) {
+ // eslint-disable-next-line no-use-before-define
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 => {
@@ -1815,7 +1835,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const scrollHeight = this.ProseRef && proseHeight;
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);
+ const setScrollHeight = () => {
+ this.dataDoc[this.fieldKey + '_scrollHeight'] = scrollHeight;
+ };
if (this.Document === this.layoutDoc || this.layoutDoc.resolvedDataDoc) {
setScrollHeight();
@@ -1833,7 +1855,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey);
sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey);
- setSidebarHeight = (height: number) => (this.dataDoc[this.SidebarKey + '_height'] = height);
+ setSidebarHeight = (height: number) => {
+ this.dataDoc[this.SidebarKey + '_height'] = height;
+ };
sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this._props.PanelWidth();
sidebarScreenToLocal = () =>
this._props
@@ -1851,10 +1875,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
e,
returnFalse,
emptyFunction,
- action(e => (this._recordingDictation = !this._recordingDictation))
+ action(() => {
+ this._recordingDictation = !this._recordingDictation;
+ })
)
}>
- <FontAwesomeIcon className="formattedTextBox-audioFont" style={{ color: 'red' }} icon={'microphone'} size="sm" />
+ <FontAwesomeIcon className="formattedTextBox-audioFont" style={{ color: 'red' }} icon="microphone" size="sm" />
</div>
);
}
@@ -1883,6 +1909,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return ComponentTag === CollectionStackingView ? (
<SidebarAnnos
ref={this._sidebarRef}
+ // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
Document={this.Document}
layoutDoc={this.layoutDoc}
@@ -1902,6 +1929,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
) : (
<div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}>
<ComponentTag
+ // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
ref={this._sidebarTagRef as any}
setContentView={emptyFunction}
@@ -1924,8 +1952,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
renderDepth={this._props.renderDepth + 1}
setHeight={this.setSidebarHeight}
fitContentsToBox={this.fitContentsToBox}
- noSidebar={true}
- treeViewHideTitle={true}
+ noSidebar
+ treeViewHideTitle
fieldKey={this.layoutDoc[this.SidebarKey + '_type_collection'] === 'translation' ? `${this.fieldKey}_translation` : `${this.fieldKey}_sidebar`}
/>
</div>
@@ -1963,7 +1991,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}>
<div
className="formattedTextBox-alternateButton"
- onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => this.cycleAlternateText())}
+ onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, () => this.cycleAlternateText())}
style={{
display: this._props.isContentActive() && !SnappingManager.IsDragging ? 'flex' : 'none',
background: usePath === undefined ? 'white' : usePath === 'alternate' ? 'black' : 'gray',
@@ -2000,7 +2028,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
// prevent default if selected || child is active but this doc isn't scrollable
if (
!isNaN(height) &&
- (this._scrollRef?.scrollHeight ?? 0) <= Math.ceil((height ? height : this._props.PanelHeight()) / scale) && //
+ (this._scrollRef?.scrollHeight ?? 0) <= Math.ceil((height || this._props.PanelHeight()) / scale) && //
(this._props.rootSelected?.() || this.isAnyChildContentActive())
) {
e.preventDefault();
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index c0cb60c6d..533fefa09 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -50,7 +50,7 @@ export class FormattedTextBoxComment {
static userMark: Mark;
static textBox: FormattedTextBox | undefined;
- constructor(view: any) {
+ constructor() {
if (!FormattedTextBoxComment.tooltip) {
const tooltip = (FormattedTextBoxComment.tooltip = document.createElement('div'));
const tooltipText = (FormattedTextBoxComment.tooltipText = document.createElement('div'));
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index 8f716ad7a..0f3306bef 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -12,7 +12,7 @@ export const marks: { [index: string]: MarkSpec } = {
attrs: {
id: { default: '' },
},
- toDOM(node: any) {
+ toDOM() {
return ['div', { className: 'dummy' }, 0];
},
},
@@ -44,7 +44,7 @@ export const marks: { [index: string]: MarkSpec } = {
toDOM(node: any) {
const targethrefs = node.attrs.allAnchors.reduce((p: string, item: { href: string; title: string; anchorId: string }) => (p ? p + ' ' + item.href : item.href), '');
const anchorids = node.attrs.allAnchors.reduce((p: string, item: { href: string; title: string; anchorId: string }) => (p ? p + ' ' + item.anchorId : item.anchorId), '');
- return ['a', { id: Utils.GenerateGuid(), class: anchorids, 'data-targethrefs': targethrefs, /*'data-noPreview': 'true', */ 'data-linkdoc': node.attrs.linkDoc, title: node.attrs.title, style: `background: lightBlue` }, 0];
+ return ['a', { id: Utils.GenerateGuid(), class: anchorids, 'data-targethrefs': targethrefs, /* 'data-noPreview': 'true', */ 'data-linkdoc': node.attrs.linkDoc, title: node.attrs.title, style: `background: lightBlue` }, 0];
},
},
noAutoLinkAnchor: {
@@ -60,7 +60,7 @@ export const marks: { [index: string]: MarkSpec } = {
},
},
],
- toDOM(node: any) {
+ toDOM() {
return ['span', { 'data-noAutoLink': 'true' }, 0];
},
},
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 9c4080154..02ff661e5 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { ColorResult } from 'react-color';
import { ClientUtils, returnFalse, setupMoveUpEvents } from '../../../ClientUtils';
-import { unimplementedFunction } from '../../../Utils';
+import { emptyFunction, unimplementedFunction } from '../../../Utils';
import { Doc, Opt } from '../../../fields/Doc';
import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT';
import { DocumentType } from '../../documents/DocumentTypes';
@@ -50,8 +50,8 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
- public Highlight: (color: string) => Opt<Doc> = (color: string) => undefined;
- public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => undefined;
+ public Highlight: (color: string) => Opt<Doc> = (/* color: string */) => undefined;
+ public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = emptyFunction;
public Delete: () => void = unimplementedFunction;
public PinToPres: () => void = unimplementedFunction;
public MakeTargetToggle: () => void = unimplementedFunction;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 60c6402d4..3fb914423 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1,3 +1,5 @@
+/* eslint-disable default-param-last */
+/* eslint-disable no-use-before-define */
import { action, computed, makeObservable, observable, ObservableMap, ObservableSet, runInAction } from 'mobx';
import { computedFn } from 'mobx-utils';
import { alias, map, serializable } from 'serializr';
@@ -35,7 +37,7 @@ export namespace Field {
* @returns string representation of the field
*/
export function toKeyValueString(doc: Doc, key: string, showComputedValue?: boolean): string {
- const onDelegate = !Doc.IsDataProto(doc) && Object.keys(doc).includes(key.replace(/^_/, ''));
+ const isOnDelegate = !Doc.IsDataProto(doc) && Object.keys(doc).includes(key.replace(/^_/, ''));
const field = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
const valFunc = (field: FieldType): string => {
const res =
@@ -53,7 +55,7 @@ export namespace Field {
.trim()
.replace(/^new List\((.*)\)$/, '$1');
};
- return !Field.IsField(field) ? (key.startsWith('_') ? '=' : '') : (onDelegate ? '=' : '') + valFunc(field);
+ return !Field.IsField(field) ? (key.startsWith('_') ? '=' : '') : (isOnDelegate ? '=' : '') + valFunc(field);
}
export function toScriptString(field: FieldType) {
switch (typeof field) {
@@ -79,7 +81,7 @@ export namespace Field {
// as a kind of macro to include the content of those documents
Doc.MyPublishedDocs.forEach(doc => {
const regexMultilineFlag = 'm';
- const regex = new RegExp(`^\\^${StrCast(doc.title).replace(/[\(\)]*/g, '')}\\s`, regexMultilineFlag); // need to remove characters that can cause the regular expression to be invalid
+ const regex = new RegExp(`^\\^${StrCast(doc.title).replace(/[()]*/g, '')}\\s`, regexMultilineFlag); // need to remove characters that can cause the regular expression to be invalid
const sections = (Cast(doc.text, RichTextField, null)?.Text ?? '').split('--DOCDATA--');
if (script.match(regex)) {
script = script.replace(regex, sections[0]) + (sections.length > 1 ? sections[1] : '');
@@ -148,19 +150,24 @@ export const ReverseHierarchyMap: Map<string, { level: aclLevel; acl: symbol; im
// caches the document access permissions for the current user.
// this recursively updates all protos as well.
export function updateCachedAcls(doc: Doc) {
- if (!doc) return;
-
- const target = (doc as any)?.__fieldTuples ?? doc;
- const permissions: { [key: string]: symbol } = !target.author || target.author === ClientUtils.CurrentUserEmail ? { 'acl-Me': AclAdmin } : {};
- Object.keys(target).filter(key => key.startsWith('acl') && (permissions[key] = ReverseHierarchyMap.get(StrCast(target[key]))!.acl));
- if (Object.keys(permissions).length || doc[DocAcl]?.length) {
- runInAction(() => (doc[DocAcl] = permissions));
- }
+ if (doc) {
+ const target = (doc as any)?.__fieldTuples ?? doc;
+ const permissions: { [key: string]: symbol } = !target.author || target.author === ClientUtils.CurrentUserEmail ? { 'acl-Me': AclAdmin } : {};
+ Object.keys(target).forEach(key => {
+ key.startsWith('acl') && (permissions[key] = ReverseHierarchyMap.get(StrCast(target[key]))!.acl);
+ });
+ if (Object.keys(permissions).length || doc[DocAcl]?.length) {
+ runInAction(() => {
+ doc[DocAcl] = permissions;
+ });
+ }
- if (doc.proto instanceof Promise) {
- doc.proto.then(proto => updateCachedAcls(DocCast(proto)));
- return doc.proto;
+ if (doc.proto instanceof Promise) {
+ doc.proto.then(proto => updateCachedAcls(DocCast(proto)));
+ return doc.proto;
+ }
}
+ return undefined;
}
@scriptingGlobal
@@ -267,9 +274,9 @@ export class Doc extends RefField {
return Reflect.getOwnPropertyDescriptor(target, prop);
}
return {
- configurable: true, //TODO Should configurable be true?
+ configurable: true, // TODO Should configurable be true?
enumerable: true,
- value: 0, //() => target.__fieldTuples[prop])
+ value: 0, // () => target.__fieldTuples[prop])
};
},
deleteProperty: deleteProperty,
@@ -281,7 +288,8 @@ export class Doc extends RefField {
if (!id || forceSave) {
DocServer.CreateField(docProxy);
}
- return docProxy;
+ // eslint-disable-next-line no-constructor-return
+ return docProxy; // need to return the proxy from the constructor so that all our added fields will get called
}
[key: string]: FieldResult;
@@ -293,6 +301,7 @@ export class Doc extends RefField {
private set __fieldTuples(value) {
// called by deserializer to set all fields in one shot
this[FieldTuples] = value;
+ // eslint-disable-next-line no-restricted-syntax
for (const key in value) {
const field = value[key];
field !== undefined && (this[FieldKeys][key] = true);
@@ -345,7 +354,7 @@ export class Doc extends RefField {
let renderFieldKey: any;
const layoutField = templateLayoutDoc[StrCast(templateLayoutDoc.layout_fieldKey, 'layout')];
if (typeof layoutField === 'string') {
- renderFieldKey = layoutField.split("fieldKey={'")[1].split("'")[0]; //layoutField.split("'")[1];
+ [renderFieldKey] = layoutField.split("fieldKey={'")[1].split("'"); // layoutField.split("'")[1];
} else {
return Cast(layoutField, Doc, null);
}
@@ -361,6 +370,7 @@ export class Doc extends RefField {
for (const key in set) {
const fprefix = 'fields.';
if (!key.startsWith(fprefix)) {
+ // eslint-disable-next-line no-continue
continue;
}
const fKey = key.substring(fprefix.length);
@@ -380,6 +390,7 @@ export class Doc extends RefField {
const writeMode = DocServer.getFieldWriteMode(fKey);
if (fKey.startsWith('acl') || writeMode !== DocServer.WriteMode.Playground) {
delete this[CachedUpdates][fKey];
+ // eslint-disable-next-line no-await-in-loop
await fn();
} else {
this[CachedUpdates][fKey] = fn;
@@ -390,6 +401,7 @@ export class Doc extends RefField {
if (unset) {
for (const key in unset) {
if (!key.startsWith('fields.')) {
+ // eslint-disable-next-line no-continue
continue;
}
const fKey = key.substring(7);
@@ -400,6 +412,7 @@ export class Doc extends RefField {
};
if (sameAuthor || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) {
delete this[CachedUpdates][fKey];
+ // eslint-disable-next-line no-await-in-loop
await fn();
} else {
this[CachedUpdates][fKey] = fn;
@@ -475,8 +488,8 @@ export namespace Doc {
// 2) if the data doc has the field, then it's written there.
// 3) if neither already has the field, then 'defaultProto' determines whether to write it to the data doc (or the embedding)
//
- export async function SetInPlace(doc: Doc, key: string, value: FieldType | undefined, defaultProto: boolean) {
- if (key.startsWith('_')) key = key.substring(1);
+ export async function SetInPlace(doc: Doc, keyIn: string, value: FieldType | undefined, defaultProto: boolean) {
+ const key = keyIn.startsWith('_') ? keyIn.substring(1) : keyIn;
const hasProto = doc[DocData] !== doc ? doc[DocData] : undefined;
const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1;
const onProto = hasProto && Object.getOwnPropertyNames(hasProto).indexOf(key) !== -1;
@@ -561,7 +574,7 @@ export namespace Doc {
* @returns true if successful, false otherwise.
*/
export function RemoveDocFromList(listDoc: Doc, fieldKey: string | undefined, doc: Doc, ignoreProto = false) {
- const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc);
+ const key = fieldKey || Doc.LayoutFieldKey(listDoc);
const list = Doc.Get(listDoc, key, ignoreProto) === undefined ? (listDoc[DocData][key] = new List<Doc>()) : Cast(listDoc[key], listSpec(Doc));
if (list) {
const ind = list.indexOf(doc);
@@ -578,7 +591,7 @@ export namespace Doc {
* @returns true if successful, false otherwise.
*/
export function AddDocToList(listDoc: Doc, fieldKey: string | undefined, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean, ignoreProto?: boolean) {
- const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc);
+ const key = fieldKey || Doc.LayoutFieldKey(listDoc);
const list = Doc.Get(listDoc, key, ignoreProto) === undefined ? (listDoc[DocData][key] = new List<Doc>()) : Cast(listDoc[key], listSpec(Doc));
if (list) {
if (!allowDuplicates) {
@@ -595,6 +608,7 @@ export namespace Doc {
if (reversed) list.splice(0, 0, doc);
else list.push(doc);
} else {
+ // eslint-disable-next-line no-lonely-if
if (reversed) list.splice(before ? list.length - ind + 1 : list.length - ind, 0, doc);
else list.splice(before ? ind : ind + 1, 0, doc);
}
@@ -662,7 +676,9 @@ export namespace Doc {
await Promise.all(
Object.keys(doc).map(async key => {
if (filter.includes(key)) return;
- const assignKey = (val: any) => (copy[key] = val);
+ const assignKey = (val: any) => {
+ copy[key] = val;
+ };
const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
const field = ProxyField.WithoutProxy(() => doc[key]);
const copyObjectField = async (field: ObjectField) => {
@@ -714,7 +730,8 @@ export namespace Doc {
} else if (field instanceof ObjectField) {
await copyObjectField(field);
} else if (field instanceof Promise) {
- debugger; //This shouldn't happen...
+ // eslint-disable-next-line no-debugger
+ debugger; // This shouldn't happen...
} else {
assignKey(field);
}
@@ -741,7 +758,7 @@ export namespace Doc {
visited.add(clone);
Object.keys(clone)
.filter(key => key !== 'cloneOf')
- .map(key => {
+ .forEach(key => {
const docAtKey = DocCast(clone[key]);
if (docAtKey && !Doc.IsSystem(docAtKey)) {
if (!Array.from(cloneMap.values()).includes(docAtKey)) {
@@ -763,13 +780,13 @@ export namespace Doc {
const copy = await Doc.makeClone(doc, cloneMap, linkMap, rtfMap, ['cloneOf'], doc.embedContainer ? [DocCast(doc.embedContainer)] : [], cloneLinks, cloneTemplates);
const repaired = new Set<Doc>();
const linkedDocs = Array.from(linkMap.values());
- linkedDocs.map(link => Doc.AddLink?.(link, true));
- rtfMap.map(({ copy, key, field }) => {
- const replacer = (match: any, attr: string, id: string, offset: any, string: any) => {
+ linkedDocs.forEach(link => Doc.AddLink?.(link, true));
+ rtfMap.forEach(({ copy, key, field }) => {
+ const replacer = (match: any, attr: string, id: string /* , offset: any, string: any */) => {
const mapped = cloneMap.get(id);
return attr + '"' + (mapped ? mapped[Id] : id) + '"';
};
- const replacer2 = (match: any, href: string, id: string, offset: any, string: any) => {
+ const replacer2 = (match: any, href: string, id: string /* , offset: any, string: any */) => {
const mapped = cloneMap.get(id);
return href + (mapped ? mapped[Id] : id);
};
@@ -778,7 +795,7 @@ export namespace Doc {
copy[key] = new RichTextField(field.Data.replace(docidsearch, replacer).replace(re, replacer2), field.Text);
});
const clonedDocs = [...Array.from(cloneMap.values()), ...linkedDocs];
- clonedDocs.map(clone => Doc.repairClone(clone, cloneMap, cloneTemplates, repaired));
+ clonedDocs.forEach(clone => Doc.repairClone(clone, cloneMap, cloneTemplates, repaired));
return { clone: copy, map: cloneMap, linkMap };
}
@@ -809,6 +826,7 @@ export namespace Doc {
if (templateLayoutDoc.resolvedDataDoc === targetDoc[DocData]) {
expandedTemplateLayout = templateLayoutDoc; // reuse an existing template layout if its for the same document with the same params
} else {
+ // eslint-disable-next-line no-param-reassign
templateLayoutDoc.resolvedDataDoc && (templateLayoutDoc = DocCast(templateLayoutDoc.proto, templateLayoutDoc)); // if the template has already been applied (ie, a nested template), then use the template's prototype
if (!targetDoc[expandedLayoutFieldKey]) {
_pendingMap.add(targetDoc[Id] + expandedLayoutFieldKey);
@@ -879,6 +897,7 @@ export namespace Doc {
}
}
} else if (cfield instanceof ComputedField) {
+ /* empty */
} else if (field instanceof ObjectField) {
if (field instanceof Doc) {
Doc.FindReferences(field, references, system);
@@ -895,7 +914,8 @@ export namespace Doc {
Doc.FindReferences(field.value, references, system);
}
} else if (field instanceof Promise) {
- debugger; //This shouldn't happend...
+ // eslint-disable-next-line no-debugger
+ debugger; // This shouldn't happend...
}
}
});
@@ -925,7 +945,8 @@ export namespace Doc {
? new ProxyField(Doc.MakeCopy(doc[key] as any)) // copy the expanded render template
: ObjectField.MakeCopy(field);
} else if (field instanceof Promise) {
- debugger; //This shouldn't happend...
+ // eslint-disable-next-line no-debugger
+ debugger; // This shouldn't happend...
} else {
copy[key] = field;
}
@@ -955,7 +976,9 @@ export namespace Doc {
delegate.author = ClientUtils.CurrentUserEmail;
Object.keys(doc)
.filter(key => key.startsWith('acl'))
- .forEach(key => (delegate[key] = doc[key]));
+ .forEach(key => {
+ delegate[key] = doc[key];
+ });
title && (delegate.title = title);
delegate[Initializing] = false;
if (!Doc.IsSystem(doc)) Doc.AddEmbedding(doc, delegate);
@@ -968,7 +991,7 @@ export namespace Doc {
// (ie, the 'data' doc), and then creates another delegate of that (ie, the 'layout' doc).
// This is appropriate if you're trying to create a document that behaves like all
// regularly created documents (e.g, text docs, pdfs, etc which all have data/layout docs)
- export function MakeDelegateWithProto(doc: Doc, id?: string, title?: string) {
+ export function MakeDelegateWithProto(doc: Doc /* , id?: string, title?: string */) {
const ndoc = Doc.ApplyTemplate(doc);
if (ndoc) {
Doc.GetProto(ndoc).isDataDoc = true;
@@ -1017,7 +1040,6 @@ export namespace Doc {
!keepFieldKey && (templateField.title = metadataFieldKey);
const templateFieldValue = templateField[metadataFieldKey] || templateField[Doc.LayoutFieldKey(templateField)];
- const templateCaptionValue = templateField.caption;
// move any data that the template field had been rendering over to the template doc so that things will still be rendered
// when the template field is adjusted to point to the new metadatafield key.
// note 1: if the template field contained a list of documents, each of those documents will be converted to templates as well.
@@ -1103,7 +1125,9 @@ export namespace Doc {
return manager._searchQuery;
}
export function SetSearchQuery(query: string) {
- runInAction(() => (manager._searchQuery = query));
+ runInAction(() => {
+ manager._searchQuery = query;
+ });
}
export function UserDoc(): Doc {
return manager._user_doc;
@@ -1115,12 +1139,13 @@ export namespace Doc {
return Cast(Doc.UserDoc().myLinkDatabase, Doc, null);
}
export function SetUserDoc(doc: Doc) {
+ // eslint-disable-next-line no-return-assign
return (manager._user_doc = doc);
}
- const isSearchMatchCache = computedFn(function IsSearchMatch(doc: Doc) {
- return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(doc[DocData]) ? brushManager.SearchMatchDoc.get(doc[DocData]) : undefined;
- });
+ const isSearchMatchCache = computedFn((doc: Doc) =>
+ (brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) :
+ brushManager.SearchMatchDoc.has(doc[DocData]) ? brushManager.SearchMatchDoc.get(doc[DocData]) : undefined)); // prettier-ignore
export function IsSearchMatch(doc: Doc) {
return isSearchMatchCache(doc);
}
@@ -1166,10 +1191,14 @@ export namespace Doc {
return BrushDoc(doc, true);
}
export function UnBrushAllDocs() {
- Array.from(brushManager.BrushedDoc).forEach(action(doc => (doc[Brushed] = false)));
+ Array.from(brushManager.BrushedDoc).forEach(
+ action(doc => {
+ doc[Brushed] = false;
+ })
+ );
}
- let UnhighlightWatchers: (() => void)[] = [];
+ const UnhighlightWatchers: (() => void)[] = [];
export let UnhighlightTimer: any;
export function AddUnHighlightWatcher(watcher: () => void) {
if (UnhighlightTimer) {
@@ -1184,9 +1213,9 @@ export namespace Doc {
highlightedDocs.forEach(doc => Doc.UnHighlightDoc(doc));
document.removeEventListener('pointerdown', linkFollowUnhighlight);
}
- export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presentation_effect?: Doc) {
+ export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presentationEffect?: Doc) {
linkFollowUnhighlight();
- (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs, presentation_effect));
+ (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs, presentationEffect));
document.removeEventListener('pointerdown', linkFollowUnhighlight);
document.addEventListener('pointerdown', linkFollowUnhighlight);
if (UnhighlightTimer) clearTimeout(UnhighlightTimer);
@@ -1196,16 +1225,16 @@ export namespace Doc {
}, 5000);
}
- export var highlightedDocs = new ObservableSet<Doc>();
+ export const highlightedDocs = new ObservableSet<Doc>();
export function IsHighlighted(doc: Doc) {
if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(doc[DocData]) === AclPrivate || doc.opacity === 0) return false;
return doc[Highlight] || doc[DocData][Highlight];
}
- export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presentation_effect?: Doc) {
+ export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presentationEffect?: Doc) {
runInAction(() => {
highlightedDocs.add(doc);
doc[Highlight] = true;
- doc[Animation] = presentation_effect;
+ doc[Animation] = presentationEffect;
if (dataAndDisplayDocs && !doc.resolvedDataDoc) {
// if doc is a layout template then we don't want to highlight the proto since that will be the entire template, not just the specific layout field
highlightedDocs.add(doc[DocData]);
@@ -1294,6 +1323,7 @@ export namespace Doc {
const fields = childFilters[i].split(FilterSep); // split key:value:modifier
if (fields[0] === key && (fields[1] === value.toString() || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
if (fields[2] === modifiers && modifiers && fields[1] === value.toString()) {
+ // eslint-disable-next-line no-param-reassign
if (toggle) modifiers = 'remove';
else return;
}
@@ -1318,9 +1348,12 @@ export namespace Doc {
return [Number(childFiltersByRanges[i + 1]), Number(childFiltersByRanges[i + 2])];
}
}
+ return undefined;
}
export function assignDocToField(doc: Doc, field: string, id: string) {
- DocServer.GetRefField(id).then(layout => layout instanceof Doc && (doc[field] = layout));
+ DocServer.GetRefField(id).then(layout => {
+ layout instanceof Doc && (doc[field] = layout);
+ });
return id;
}
@@ -1395,6 +1428,7 @@ export namespace Doc {
case DocumentType.EQUATION: return 'calculator';
case DocumentType.SIMULATION: return 'rocket';
case DocumentType.CONFIG: return 'folder-closed';
+ default:
}
return 'question';
}
@@ -1413,6 +1447,7 @@ export namespace Doc {
const response = await fetch(upload, { method: 'POST', body: formData });
const json = await response.json();
if (json !== 'error') {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
const docs = await DocServer.GetRefFields(json.docids as string[]);
const doc = DocCast(await DocServer.GetRefField(json.id));
const links = await DocServer.GetRefFields(json.linkids as string[]);
@@ -1478,6 +1513,7 @@ export namespace Doc {
*/
export function FromJson({ data, title, appendToExisting, excludeEmptyObjects }: JsonConversionOpts): Opt<Doc> {
if (excludeEmptyObjects === undefined) {
+ // eslint-disable-next-line no-param-reassign
excludeEmptyObjects = true;
}
if (data === undefined || data === null || ![...primitives, 'object'].includes(typeof data)) {
@@ -1517,12 +1553,12 @@ export namespace Doc {
if (hasEntries || !excludeEmptyObjects) {
const resolved = target ?? new Doc();
if (hasEntries) {
- let result: Opt<FieldType>;
- Object.keys(object).map(key => {
+ Object.keys(object).forEach(key => {
// if excludeEmptyObjects is true, any qualifying conversions from toField will
// be undefined, and thus the results that would have
// otherwise been empty (List or Doc)s will just not be written
- if ((result = toField(object[key], excludeEmptyObjects, key))) {
+ const result = toField(object[key], excludeEmptyObjects, key);
+ if (result) {
resolved[key] = result;
}
});
@@ -1530,6 +1566,7 @@ export namespace Doc {
title && (resolved.title = title);
return resolved;
}
+ return undefined;
};
/**
@@ -1545,10 +1582,13 @@ export namespace Doc {
// if excludeEmptyObjects is true, any qualifying conversions from toField will
// be undefined, and thus the results that would have
// otherwise been empty (List or Doc)s will just not be written
- list.map(item => (result = toField(item, excludeEmptyObjects)) && target.push(result));
+ list.forEach(item => {
+ (result = toField(item, excludeEmptyObjects)) && target.push(result);
+ });
if (target.length || !excludeEmptyObjects) {
return target;
}
+ return undefined;
};
const toField = (data: any, excludeEmptyObjects: boolean, title?: string): Opt<FieldType> => {
@@ -1569,58 +1609,76 @@ export namespace Doc {
export function IdToDoc(id: string) {
return DocCast(DocServer.GetCachedRefField(id));
}
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function idToDoc(id: string): any {
return IdToDoc(id);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function renameEmbedding(doc: any) {
return StrCast(doc[DocData].title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`;
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function getProto(doc: any) {
return Doc.GetProto(doc);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function getDocTemplate(doc?: any) {
return Doc.getDocTemplate(doc);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function getEmbedding(doc: any) {
return Doc.MakeEmbedding(doc);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function getCopy(doc: any, copyProto: any) {
return doc.isTemplateDoc ? Doc.MakeDelegateWithProto(doc) : Doc.MakeCopy(doc, copyProto);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function copyField(field: any) {
return Field.Copy(field);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function docList(field: any) {
return DocListCast(field);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function addDocToList(doc: Doc, field: string, added: Doc) {
return Doc.AddDocToList(doc, field, added);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setInPlace(doc: any, field: any, value: any) {
return Doc.SetInPlace(doc, field, value, false);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function sameDocs(doc1: any, doc2: any) {
return Doc.AreProtosEqual(doc1, doc2);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function assignDoc(doc: Doc, field: string, id: string) {
return Doc.assignDocToField(doc, field, id);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function docCastAsync(doc: FieldResult): any {
return Cast(doc, Doc);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function activePresentationItem() {
const curPres = Doc.ActivePresentation;
return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)];
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setDocFilter(container: Doc, key: string, value: any, modifiers: 'match' | 'check' | 'x' | 'remove') {
Doc.setDocFilter(container, key, value, modifiers);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setDocRangeFilter(container: Doc, key: string, range: number[]) {
Doc.setDocRangeFilter(container, key, range);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function toJavascriptString(str: string) {
return Field.toJavascriptString(str as FieldType);
});
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function RtfField() {
return RichTextField.RTFfield();
});
diff --git a/src/fields/util.ts b/src/fields/util.ts
index f87c200c1..5ed10cf05 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -380,7 +380,7 @@ export function deleteProperty(target: any, prop: string | number | symbol) {
//
export function containedFieldChangedHandler(container: List<FieldType> | Doc, prop: string | number, liveContainedField: ObjectField) {
let lastValue: FieldResult = liveContainedField instanceof ObjectField ? ObjectField.MakeCopy(liveContainedField) : liveContainedField;
- return (diff?: { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: any }, dummyServerOp?: any) => {
+ return (diff?: { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: any } /* , dummyServerOp?: any */) => {
const serializeItems = () => ({ __type: 'list', fields: diff?.items?.map((item: FieldType) => SerializationHelper.Serialize(item)) });
// prettier-ignore
const serverOp = diff?.op === '$addToSet'