aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-10-07 15:14:42 -0400
committerbobzel <zzzman@gmail.com>2024-10-07 15:14:42 -0400
commit4364cb0db3988537f6b9485146a16bc15d55e3cc (patch)
tree48c324cd66b55912585dd506675e156697c58b38
parentfbff73033b6c0f9b1214e9013c155ff085e7a737 (diff)
parent09b722789afa5d7c5edfc701978f17e4745113bc (diff)
Merge branch 'master' into alyssa-starter
-rw-r--r--src/client/documents/DocUtils.ts2
-rw-r--r--src/client/util/UndoManager.ts5
-rw-r--r--src/client/views/FilterPanel.tsx36
-rw-r--r--src/client/views/GestureOverlay.tsx3
-rw-r--r--src/client/views/Main.tsx2
-rw-r--r--src/client/views/MainView.tsx35
-rw-r--r--src/client/views/PropertiesView.tsx3
-rw-r--r--src/client/views/ScriptingRepl.tsx3
-rw-r--r--src/client/views/TagsView.tsx4
-rw-r--r--src/client/views/collections/CollectionCalendarView.tsx99
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx213
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx8
-rw-r--r--src/client/views/collections/CollectionSubView.tsx2
-rw-r--r--src/client/views/collections/CollectionView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx1
-rw-r--r--src/client/views/global/globalScripts.ts27
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx1
-rw-r--r--src/client/views/nodes/DocumentView.tsx1
-rw-r--r--src/client/views/nodes/FieldView.tsx3
-rw-r--r--src/client/views/nodes/RecordingBox/ProgressBar.tsx2
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx2
-rw-r--r--src/fields/Doc.ts8
-rw-r--r--src/fields/RichTextUtils.ts6
-rw-r--r--src/server/websocket.ts42
25 files changed, 172 insertions, 340 deletions
diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts
index acaefe783..5f54f9d0a 100644
--- a/src/client/documents/DocUtils.ts
+++ b/src/client/documents/DocUtils.ts
@@ -1,5 +1,3 @@
-/* eslint-disable prefer-destructuring */
-/* eslint-disable default-param-last */
/* eslint-disable no-use-before-define */
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { saveAs } from 'file-saver';
diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts
index ce0e7768b..07d3bb708 100644
--- a/src/client/util/UndoManager.ts
+++ b/src/client/util/UndoManager.ts
@@ -43,7 +43,6 @@ export function undoable<T>(fn: (...args: any[]) => T, batchName: string): (...a
return function (...fargs) {
const batch = UndoManager.StartBatch(batchName);
try {
- // eslint-disable-next-line prefer-rest-params
return fn.apply(undefined, fargs);
} finally {
batch.end();
@@ -51,9 +50,9 @@ export function undoable<T>(fn: (...args: any[]) => T, batchName: string): (...a
};
}
-// eslint-disable-next-line no-redeclare, @typescript-eslint/no-explicit-any
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function undoBatch(target: any, key: string | symbol, descriptor?: TypedPropertyDescriptor<any>): any;
-// eslint-disable-next-line no-redeclare, @typescript-eslint/no-explicit-any
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function undoBatch(target: any, key?: string | symbol, descriptor?: TypedPropertyDescriptor<(...args: any[]) => unknown>): any {
if (!key) {
return function (...fargs: unknown[]) {
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index e34b66963..11425e477 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -1,3 +1,4 @@
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { action, computed, makeObservable, observable, ObservableMap } from 'mobx';
@@ -12,18 +13,15 @@ import { DocData } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { List } from '../../fields/List';
import { RichTextField } from '../../fields/RichTextField';
-import { DocCast, StrCast } from '../../fields/Types';
-import { Button, CurrentUserUtils } from '../util/CurrentUserUtils';
+import { StrCast } from '../../fields/Types';
import { SearchUtil } from '../util/SearchUtil';
import { SnappingManager } from '../util/SnappingManager';
import { undoable } from '../util/UndoManager';
import { FieldsDropdown } from './FieldsDropdown';
import './FilterPanel.scss';
import { DocumentView } from './nodes/DocumentView';
-import { ButtonType } from './nodes/FontIconBox/FontIconBox';
import { Handle, Tick, TooltipRail, Track } from './nodes/SliderBox-components';
import { ObservableReactComponent } from './ObservableReactComponent';
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
interface HotKeyButtonProps {
hotKey: Doc;
@@ -159,6 +157,7 @@ const HotKeyIconButton: React.FC<HotKeyButtonProps> = observer(({ hotKey /*, sel
interface filterProps {
Document: Doc;
+ addHotKey: (hotKey: string) => void;
}
@observer
@@ -357,33 +356,6 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
};
/**
- * Allows users to add a filter hotkey to the properties panel. Will also update the multitoggle at the top menu and the
- * icontags tht are displayed on the documents themselves
- * @param hotKey tite of the new hotkey
- */
- addHotkey = (hotKey: string) => {
- const buttons = DocCast(Doc.UserDoc().myContextMenuBtns);
- const filter = DocCast(buttons.Filter);
- const title = hotKey.startsWith('#') ? hotKey.substring(1) : hotKey;
-
- const newKey: Button = {
- title,
- icon: 'question',
- toolTip: `Click to toggle the ${title}'s group's visibility`,
- btnType: ButtonType.ToggleButton,
- expertMode: false,
- toolType: '#' + title,
- funcs: {},
- scripts: { onClick: '{ return handleTags(this.toolType, _readOnly_);}' },
- };
-
- const newBtn = CurrentUserUtils.setupContextMenuBtn(newKey, filter);
- newBtn.isSystem = newBtn[DocData].isSystem = undefined;
-
- Doc.AddToFilterHotKeys(newBtn);
- };
-
- /**
* Renders the newly formed hotkey icon buttons
* @returns the buttons to be rendered
*/
@@ -472,7 +444,7 @@ export class FilterPanel extends ObservableReactComponent<filterProps> {
<div>
<div className="filterBox-select">
<div style={{ width: '100%' }}>
- <FieldsDropdown Document={this.Document} selectFunc={this.addHotkey} showPlaceholder placeholder="add a hotkey" addedFields={['acl_Guest', LinkedTo]} />
+ <FieldsDropdown Document={this.Document} selectFunc={this._props.addHotKey} showPlaceholder placeholder="add a hotkey" addedFields={['acl_Guest', LinkedTo]} />
</div>
</div>
</div>
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 5fddaec9a..afeecaa63 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -70,7 +70,6 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
@observable private _strokes: InkData[] = [];
@observable private _palette?: JSX.Element = undefined;
@observable private _clipboardDoc?: JSX.Element = undefined;
- @observable private _possibilities: JSX.Element[] = [];
@computed private get height(): number {
return 2 * Math.max(this._pointerY && this._thumbY ? this._thumbY - this._pointerY : 100, 100);
@@ -209,8 +208,8 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
const intersectArray: string[] = [];
const scribbleBounds = InkField.getBounds(scribble);
for (let i = 0; i < scribble.length - 3; i += 4) { // for each segment of scribble
+ const scribbleSeg = InkField.Segment(scribble, i);
for (let j = 0; j < inkStroke.length - 3; j += 4) { // for each segment of ink stroke
- const scribbleSeg = InkField.Segment(scribble, i);
const strokeSeg = InkField.Segment(inkStroke, j);
const strokeBounds = InkField.getBounds(strokeSeg.points.map(pt => ({ X: pt.x, Y: pt.y })));
if (intersectRect(scribbleBounds, strokeBounds)) {
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 73d2872d1..17eea585a 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -18,7 +18,6 @@ import { TrackMovements } from '../util/TrackMovements';
import { KeyManager } from './GlobalKeyHandler';
import { InkingStroke } from './InkingStroke';
import { MainView } from './MainView';
-import { CollectionCalendarView } from './collections/CollectionCalendarView';
import { CollectionDockingView } from './collections/CollectionDockingView';
import { CollectionView } from './collections/CollectionView';
import { TabDocView } from './collections/TabDocView';
@@ -128,7 +127,6 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' };
CollectionFreeFormView,
CollectionDockingView,
CollectionSchemaView,
- CollectionCalendarView,
CollectionView,
WebBox,
KeyValueBox,
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 76c67a252..a3fa1c18b 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -20,6 +20,7 @@ import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
import { Docs } from '../documents/Documents';
import { CalendarManager } from '../util/CalendarManager';
import { CaptureManager } from '../util/CaptureManager';
+import { Button, CurrentUserUtils } from '../util/CurrentUserUtils';
import { DocumentManager } from '../util/DocumentManager';
import { DragManager } from '../util/DragManager';
import { dropActionType } from '../util/DropActionTypes';
@@ -41,6 +42,7 @@ import { DashboardView } from './DashboardView';
import { DictationOverlay } from './DictationOverlay';
import { DocumentDecorations } from './DocumentDecorations';
import { GestureOverlay } from './GestureOverlay';
+import { InkTranscription } from './InkTranscription';
import { LightboxView } from './LightboxView';
import './MainView.scss';
import { ObservableReactComponent } from './ObservableReactComponent';
@@ -60,6 +62,7 @@ import { LinkMenu } from './linking/LinkMenu';
import { SchemaCSVPopUp } from './nodes/DataVizBox/SchemaCSVPopUp';
import { DocButtonState } from './nodes/DocumentLinksButton';
import { DocumentView, DocumentViewInternal } from './nodes/DocumentView';
+import { ButtonType } from './nodes/FontIconBox/FontIconBox';
import { ImageEditorData as ImageEditor } from './nodes/ImageBox';
import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
import { LinkDocPreview, LinkInfo } from './nodes/LinkDocPreview';
@@ -73,9 +76,8 @@ import GenerativeFill from './nodes/generativeFill/GenerativeFill';
import { PresBox } from './nodes/trails';
import { AnchorMenu } from './pdf/AnchorMenu';
import { GPTPopup } from './pdf/GPTPopup/GPTPopup';
-import { TopBar } from './topbar/TopBar';
import { SmartDrawHandler } from './smartdraw/SmartDrawHandler';
-import { InkTranscription } from './InkTranscription';
+import { TopBar } from './topbar/TopBar';
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore
@@ -851,6 +853,33 @@ export class MainView extends ObservableReactComponent<object> {
return true;
};
+ /**
+ * Allows users to add a filter hotkey to the properties panel. Will also update the multitoggle at the top menu and the
+ * icontags tht are displayed on the documents themselves
+ * @param hotKey tite of the new hotkey
+ */
+ addHotKey = (hotKey: string) => {
+ const buttons = DocCast(Doc.UserDoc().myContextMenuBtns);
+ const filter = DocCast(buttons.Filter);
+ const title = hotKey.startsWith('#') ? hotKey.substring(1) : hotKey;
+
+ const newKey: Button = {
+ title,
+ icon: 'question',
+ toolTip: `Click to toggle the ${title}'s group's visibility`,
+ btnType: ButtonType.ToggleButton,
+ expertMode: false,
+ toolType: '#' + title,
+ funcs: {},
+ scripts: { onClick: '{ return handleTags(this.toolType, _readOnly_);}' },
+ };
+
+ const newBtn = CurrentUserUtils.setupContextMenuBtn(newKey, filter);
+ newBtn.isSystem = newBtn[DocData].isSystem = undefined;
+
+ Doc.AddToFilterHotKeys(newBtn);
+ };
+
@computed get mainInnerContent() {
const leftMenuFlyoutWidth = this._leftMenuFlyoutWidth + this.leftMenuWidth();
const width = this.propertiesWidth() + leftMenuFlyoutWidth;
@@ -879,7 +908,7 @@ export class MainView extends ObservableReactComponent<object> {
)}
<div className="properties-container" style={{ width: this.propertiesWidth(), color: SnappingManager.userColor }}>
<div style={{ display: this.propertiesWidth() < 10 ? 'none' : undefined }}>
- <PropertiesView styleProvider={DefaultStyleProvider} addDocTab={DocumentViewInternal.addDocTabFunc} width={this.propertiesWidth()} height={this.propertiesHeight()} />
+ <PropertiesView styleProvider={DefaultStyleProvider} addHotKey={this.addHotKey} addDocTab={DocumentViewInternal.addDocTabFunc} width={this.propertiesWidth()} height={this.propertiesHeight()} />
</div>
</div>
</div>
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 71d184497..371d34173 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -50,6 +50,7 @@ interface PropertiesViewProps {
height: number;
styleProvider?: StyleProviderFuncType;
addDocTab: (doc: Doc, where: OpenWhere) => boolean;
+ addHotKey: (hotKey: string) => void;
}
@observer
@@ -1279,7 +1280,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
return (
<PropertiesSection title="Filters" isOpen={this.openFilters} setIsOpen={action(bool => { this.openFilters = bool; })} onDoubleClick={this.CloseAll}>
<div className="propertiesView-content filters" style={{ position: 'relative', height: 'auto' }}>
- <FilterPanel Document={this.selectedDoc ?? Doc.ActiveDashboard!} />
+ <FilterPanel Document={this.selectedDoc ?? Doc.ActiveDashboard!} addHotKey={this._props.addHotKey}/>
</div>
</PropertiesSection>
); // prettier-ignore
diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx
index 2de867746..8ab91a6b5 100644
--- a/src/client/views/ScriptingRepl.tsx
+++ b/src/client/views/ScriptingRepl.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/no-array-index-key */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
@@ -182,7 +181,7 @@ export class ScriptingRepl extends ObservableReactComponent<object> {
this.maybeScrollToBottom();
return;
}
- const result = undoable(() => script.run({}, e => this.commands.push({ command: this.commandString, result: e as string })), 'run:' + this.commandString)();
+ const result = undoable(() => script.run({}, err => this.commands.push({ command: this.commandString, result: err as string })), 'run:' + this.commandString)();
if (result.success) {
this.commands.push({ command: this.commandString, result: result.result });
this.commandsHistory.push(this.commandString);
diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx
index 9858e7b61..072cae3af 100644
--- a/src/client/views/TagsView.tsx
+++ b/src/client/views/TagsView.tsx
@@ -84,9 +84,7 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
*/
public static allDocsWithTag = (tag: string) => DocListCast(TagItem.findTagCollectionDoc(tag)?.[DocData].docs);
- public static docHasTag = (doc: Doc, tag: string) => {
- return StrListCast(doc?.tags).includes(tag);
- };
+ public static docHasTag = (doc: Doc, tag: string) => StrListCast(doc?.tags).includes(tag);
/**
* Adds a tag to the metadata of this document and adds the Doc to the corresponding tag collection Doc (or creates it)
* @param tag tag string
diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx
deleted file mode 100644
index 0ea9f8ebc..000000000
--- a/src/client/views/collections/CollectionCalendarView.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import { computed, makeObservable } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { emptyFunction } from '../../../Utils';
-import { dateRangeStrToDates, returnTrue } from '../../../ClientUtils';
-import { Doc, DocListCast } from '../../../fields/Doc';
-import { StrCast } from '../../../fields/Types';
-import { CollectionStackingView } from './CollectionStackingView';
-import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
-
-@observer
-export class CollectionCalendarView extends CollectionSubView() {
- constructor(props: SubCollectionViewProps) {
- super(props);
- makeObservable(this);
- }
-
- componentDidMount(): void {}
-
- componentWillUnmount(): void {}
-
- @computed get allCalendars() {
- return this.childDocs; // returns a list of docs (i.e. calendars)
- }
-
- removeCalendar = () => {};
-
- addCalendar = (/* doc: Doc | Doc[], annotationKey?: string | undefined */): boolean =>
- // bring up calendar modal with option to create a calendar
- true;
-
- _stackRef = React.createRef<CollectionStackingView>();
-
- panelHeight = () => this._props.PanelHeight() - 40; // this should be the height of the stacking view. For now, it's the hieight of the calendar view minus 40 to allow for a title
-
- // most recent calendar should come first
- sortByMostRecentDate = (calendarA: Doc, calendarB: Doc) => {
- const aDateRangeStr = StrCast(DocListCast(calendarA.data).lastElement()?.date_range);
- const bDateRangeStr = StrCast(DocListCast(calendarB.data).lastElement()?.date_range);
-
- const { start: aFromDate, end: aToDate } = dateRangeStrToDates(aDateRangeStr);
- const { start: bFromDate, end: bToDate } = dateRangeStrToDates(bDateRangeStr);
-
- if (aFromDate > bFromDate) {
- return -1; // a comes first
- }
- if (aFromDate < bFromDate) {
- return 1; // b comes first
- }
- // start dates are the same
- if (aToDate > bToDate) {
- return -1; // a comes first
- }
- if (aToDate < bToDate) {
- return 1; // b comes first
- }
- return 0; // same start and end dates
- };
-
- screenToLocalTransform = () =>
- this._props
- .ScreenToLocalTransform()
- .translate(Doc.NativeWidth(this.Document), 0)
- .scale(this._props.NativeDimScaling?.() || 1);
-
- get calendarsKey() {
- return this._props.fieldKey;
- }
-
- render() {
- return (
- <div className="collectionCalendarView">
- <CollectionStackingView
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...this._props}
- setContentViewBox={emptyFunction}
- ref={this._stackRef}
- PanelHeight={this.panelHeight}
- PanelWidth={this._props.PanelWidth}
- sortFunc={this.sortByMostRecentDate}
- setHeight={undefined}
- isAnnotationOverlay={false}
- // select={emptyFunction} What does this mean?
- isAnyChildContentActive={returnTrue} // ??
- dontCenter="y"
- // childDocumentsActive={}
- // whenChildContentsActiveChanged={}
- childHideDecorationTitle={false}
- removeDocument={this.removeDocument} // will calendar automatically be removed from myCalendars
- moveDocument={this.moveDocument}
- addDocument={this.addCalendar}
- ScreenToLocalTransform={this.screenToLocalTransform}
- renderDepth={this._props.renderDepth + 1}
- fieldKey={this.calendarsKey}
- />
- </div>
- );
- }
-}
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 37612ff5f..842724e39 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -2,7 +2,6 @@ import { IReactionDisposer, ObservableMap, action, computed, makeObservable, obs
import { observer } from 'mobx-react';
import * as React from 'react';
import { ClientUtils, DashColor, returnFalse, returnZero } from '../../../ClientUtils';
-import { emptyFunction } from '../../../Utils';
import { Doc } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
@@ -13,7 +12,6 @@ import { gptImageLabel } from '../../apis/gpt/GPT';
import { DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { dropActionType } from '../../util/DropActionTypes';
-import { SelectionManager } from '../../util/SelectionManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoable } from '../../util/UndoManager';
@@ -23,12 +21,12 @@ import { DocumentView } from '../nodes/DocumentView';
import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
import './CollectionCardDeckView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
+import { computedFn } from 'mobx-utils';
enum cardSortings {
Time = 'time',
Type = 'type',
Color = 'color',
- Custom = 'custom',
Chat = 'chat',
Tag = 'tag',
None = '',
@@ -46,14 +44,13 @@ export class CollectionCardView extends CollectionSubView() {
private _dropDisposer?: DragManager.DragDropDisposer;
private _disposers: { [key: string]: IReactionDisposer } = {};
private _textToDoc = new Map<string, Doc>();
- private _dropped = false; // indicate when a card doc has just moved;
+ private _dropped = false; // set when a card doc has just moved and the drop method has been called - prevents the pointerUp method from hiding doc decorations (which needs to be done when clicking on a card to animate it to front/center)
@observable _forceChildXf = 0;
@observable _hoveredNodeIndex = -1;
@observable _docRefs = new ObservableMap<Doc, DocumentView>();
@observable _maxRowCount = 10;
@observable _docDraggedIndex: number = -1;
- @observable overIndex: number = -1;
static imageUrlToBase64 = async (imageUrl: string): Promise<string> => {
try {
@@ -101,7 +98,6 @@ export class CollectionCardView extends CollectionSubView() {
componentDidMount() {
this._props.setContentViewBox?.(this);
- // Reaction to cardSort changes
this._disposers.sort = reaction(
() => GPTPopup.Instance.visible,
isVis => {
@@ -135,8 +131,7 @@ export class CollectionCardView extends CollectionSubView() {
}
/**
- * The child documents to be rendered-- either all of them except the Links or the docs in the currently active
- * custom group
+ * The child documents to be rendered-- everything other than ink/link docs (which are marks as being svg's)
*/
@computed get childDocsWithoutLinks() {
return this.childDocs.filter(l => !l.layout_isSvg);
@@ -155,8 +150,7 @@ export class CollectionCardView extends CollectionSubView() {
*/
quizMode = () => {
const randomIndex = Math.floor(Math.random() * this.childDocs.length);
- SelectionManager.DeselectAll();
- DocumentView.SelectView(DocumentView.getDocumentView(this.childDocs[randomIndex]), false);
+ DocumentView.getDocumentView(this.childDocs[randomIndex])?.select(false);
};
/**
@@ -168,29 +162,15 @@ export class CollectionCardView extends CollectionSubView() {
@action
setHoveredNodeIndex = (index: number) => {
- if (!DocumentView.SelectedDocs().includes(this.childDocs[index])) {
- this._hoveredNodeIndex = index;
- }
+ if (!SnappingManager.IsDragging) this._hoveredNodeIndex = index;
};
- /**
- * Translates the hovered node to the center of the screen
- * @param index
- * @returns
- */
- translateHover = (index: number) => (this._hoveredNodeIndex === index && !DocumentView.SelectedDocs().includes(this.childDocs[index]) ? -50 : 0);
-
- isSelected = (index: number) => DocumentView.SelectedDocs().includes(this.childDocs[index]);
-
- /**
- * Returns all the documents except the one that's currently selected
- */
- inactiveDocs = () => this.childDocsWithoutLinks.filter(d => !DocumentView.SelectedDocs().includes(d));
+ isSelected = (doc: Doc) => this._docRefs.get(doc)?.IsSelected;
childPanelWidth = () => NumCast(this.layoutDoc.childPanelWidth, this._props.PanelWidth() / 2);
childPanelHeight = () => this._props.PanelHeight() * this.fitContentScale;
onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
- isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive();
- isChildContentActive = () => !!this.isContentActive();
+ isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this.isAnyChildContentActive();
+ isAnyChildContentActive = this._props.isAnyChildContentActive;
/**
* Returns the degree to rotate a card dependind on the amount of cards in their row and their index in said row
@@ -202,13 +182,14 @@ export class CollectionCardView extends CollectionSubView() {
if (amCards == 1) return 0;
const possRotate = -30 + index * (30 / ((amCards - (amCards % 2)) / 2));
- const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2)));
-
- if (amCards % 2 === 0 && possRotate === 0) {
- return possRotate + Math.abs(-30 + (index - 1) * (30 / (amCards / 2)));
- }
- if (amCards % 2 === 0 && index > (amCards + 1) / 2) {
- return possRotate + stepMag;
+ if (amCards % 2 === 0) {
+ if (possRotate === 0) {
+ return possRotate + Math.abs(-30 + (index - 1) * (30 / (amCards / 2)));
+ }
+ if (index > (amCards + 1) / 2) {
+ const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2)));
+ return possRotate + stepMag;
+ }
}
return possRotate;
@@ -274,22 +255,13 @@ export class CollectionCardView extends CollectionSubView() {
/**
* Checks to see if a card is being dragged and calls the appropriate methods if so
- * @param e the current pointer event
*/
-
@action
onPointerMove = (x: number, y: number) => {
this._docDraggedIndex = DragManager.docsBeingDragged.length ? this.findCardDropIndex(x, y) : -1;
};
/**
- * Handles external drop of images/PDFs etc from outside Dash.
- */
- onExternalDrop = async (e: React.DragEvent): Promise<void> => {
- super.onExternalDrop(e, {});
- };
-
- /**
* Resets all the doc dragging vairables once a card is dropped
* @param e
* @param de drop event
@@ -326,7 +298,7 @@ export class CollectionCardView extends CollectionSubView() {
}
/**
- * Used to determine how to sort cards based on tags. The lestmost tags are given lower values while cards to the right are
+ * Used to determine how to sort cards based on tags. The leftmost tags are given lower values while cards to the right are
* given higher values. Decimals are used to determine placement for cards with multiple tags
* @param doc the doc whose value is being determined
* @returns its value based on its tags
@@ -352,24 +324,14 @@ export class CollectionCardView extends CollectionSubView() {
docs.sort((docA, docB) => {
const [typeA, typeB] = (() => {
switch (sortType) {
- case cardSortings.Time:
- return [DateCast(docA.author_date)?.date ?? Date.now(), DateCast(docB.author_date)?.date ?? Date.now()];
- case cardSortings.Color: {
- const d1 = DashColor(StrCast(docA.backgroundColor));
- const d2 = DashColor(StrCast(docB.backgroundColor));
- return [d1.hsv().hue(), d2.hsv().hue()];
- }
- case cardSortings.Tag:
- return [this.tagValue(docA) ?? 9999, this.tagValue(docB) ?? 9999];
- case cardSortings.Chat:
- return [NumCast(docA.chatIndex) ?? 9999, NumCast(docB.chatIndex) ?? 9999];
- default:
- return [StrCast(docA.type), StrCast(docB.type)];
+ default:
+ case cardSortings.Type: return [StrCast(docA.type), StrCast(docB.type)];
+ case cardSortings.Chat: return [NumCast(docA.chatIndex, 9999), NumCast(docB.chatIndex,9999)];
+ case cardSortings.Time: return [DateCast(docA.author_date)?.date ?? Date.now(), DateCast(docB.author_date)?.date ?? Date.now()];
+ case cardSortings.Color:return [DashColor(StrCast(docA.backgroundColor)).hsv().hue(), DashColor(StrCast(docB.backgroundColor)).hsv().hue()];
}
- })();
-
- const out = typeA < typeB ? -1 : typeA > typeB ? 1 : 0;
- return isDesc ? out : -out;
+ })(); //prettier-ignore
+ return (typeA < typeB ? -1 : typeA > typeB ? 1 : 0) * (isDesc ? 1 : -1);
});
if (dragIndex !== -1) {
const draggedDoc = DragManager.docsBeingDragged[0];
@@ -382,6 +344,15 @@ export class CollectionCardView extends CollectionSubView() {
return docs;
};
+ isChildContentActive = () =>
+ this._props.isContentActive?.() === false
+ ? false
+ : this._props.isDocumentActive?.() && (this._props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive))
+ ? true
+ : this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
+ ? false
+ : undefined;
+
displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => (
<DocumentView
{...this._props}
@@ -396,13 +367,14 @@ export class CollectionCardView extends CollectionSubView() {
LayoutTemplateString={this._props.childLayoutString}
containerViewPath={this.childContainerViewPath}
ScreenToLocalTransform={screenToLocalTransform} // makes sure the box wrapper thing is in the right spot
- isContentActive={emptyFunction}
isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
PanelWidth={this.childPanelWidth}
PanelHeight={this.childPanelHeight}
dontCenter="y" // Don't center it vertically, because the grid it's in is already doing that and we don't want to do it twice.
dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
showTags={BoolCast(this.layoutDoc.showChildTags)}
+ whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+ isContentActive={this.isChildContentActive}
dontHideOnDrag
/>
);
@@ -416,13 +388,11 @@ export class CollectionCardView extends CollectionSubView() {
if (this.sortedDocs.length < this._maxRowCount) {
return this.sortedDocs.length;
}
- // 13 - 3 = 10
const totalCards = this.sortedDocs.length;
// if 9 or less
if (index < totalCards - (totalCards % this._maxRowCount)) {
return this._maxRowCount;
}
- // (3)
return totalCards % this._maxRowCount;
};
/**
@@ -441,19 +411,18 @@ export class CollectionCardView extends CollectionSubView() {
translateOverflowX = (realIndex: number, calcRowCards: number) => (realIndex < this._maxRowCount ? 0 : (this._maxRowCount - calcRowCards) * (this.childPanelWidth() / 2));
/**
- * Determines how far to translate a card in the y direction depending on its index, whether or not its being hovered, or if it's selected
- * @param isHovered
- * @param isSelected
- * @param realIndex
- * @param amCards
- * @param calcRowIndex
- * @returns
+ * Determines how far to translate a card in the y direction depending on its index and if it's selected
+ * @param isActive whether the card is focused for interaction
+ * @param realIndex index of card from start of deck
+ * @param amCards ??
+ * @param calcRowIndex index of card from start of row
+ * @returns Y translation of card
*/
- calculateTranslateY = (isHovered: boolean, isSelected: boolean, realIndex: number, amCards: number, calcRowIndex: number) => {
+ calculateTranslateY = (isActive: boolean, realIndex: number, amCards: number, calcRowIndex: number) => {
const rowHeight = (this._props.PanelHeight() * this.fitContentScale) / this.numRows;
const rowIndex = Math.trunc(realIndex / this._maxRowCount);
const rowToCenterShift = this.numRows / 2 - rowIndex;
- if (isSelected) return rowToCenterShift * rowHeight - rowHeight / 2;
+ if (isActive) return rowToCenterShift * rowHeight - rowHeight / 2;
if (amCards == 1) return 50 * this.fitContentScale;
return this.translateY(amCards, calcRowIndex, realIndex);
};
@@ -576,15 +545,43 @@ export class CollectionCardView extends CollectionSubView() {
await this.childPairStringListAndUpdateSortDesc();
};
+ childScreenToLocal = computedFn((doc: Doc, index: number, calcRowIndex: number, isSelected: boolean, amCards: number) => () => {
+ // need to explicitly trigger an invalidation since we're reading everything from the Dom
+ this._forceChildXf;
+ this._props.ScreenToLocalTransform();
+
+ const dref = this._docRefs.get(doc);
+ const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
+ if (!scale) return new Transform(0, 0, 0);
+
+ return new Transform(-translateX + (dref?.centeringX || 0) * scale,
+ -translateY + (dref?.centeringY || 0) * scale, 1)
+ .scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore
+ });
+
+ cardPointerUp = action((doc: Doc) => {
+ // if a card doc has just moved, or a card is selected and in front, then ignore this event
+ if (this.isSelected(doc) || this._dropped) {
+ this._dropped = false;
+ } else {
+ // otherwise, turn off documentDecorations becase we're in a selection transition and want to avoid artifacts.
+ // Turn them back on when the animation has completed and the render and backend structures are in synch
+ SnappingManager.SetIsResizing(doc[Id]);
+ setTimeout(
+ action(() => {
+ SnappingManager.SetIsResizing(undefined);
+ this._forceChildXf++;
+ }),
+ 1000
+ );
+ }
+ });
+
/**
* Actually renders all the cards
*/
@computed get renderCards() {
- const sortedDocs = this.sortedDocs;
- const anySelected = this.childDocs.some(doc => DocumentView.SelectedDocs().includes(doc));
- const isEmpty = this.childDocsWithoutLinks.length === 0;
-
- if (isEmpty) {
+ if (!this.childDocsWithoutLinks.length) {
return (
<span className="no-card-span" style={{ width: ` ${this._props.PanelWidth()}px`, height: ` ${this._props.PanelHeight()}px` }}>
Sorry ! There are no cards in this group
@@ -593,31 +590,17 @@ export class CollectionCardView extends CollectionSubView() {
}
// Map sorted documents to their rendered components
- return sortedDocs.map((doc, index) => {
- const realIndex = sortedDocs.indexOf(doc);
- const calcRowIndex = this.overflowIndexCalc(realIndex);
- const amCards = this.overflowAmCardsCalc(realIndex);
+ return this.sortedDocs.map((doc, index) => {
+ const calcRowIndex = this.overflowIndexCalc(index);
+ const amCards = this.overflowAmCardsCalc(index);
const view = DocumentView.getDocumentView(doc, this.DocumentView?.());
- const isSelected = view?.ComponentView?.isAnyChildContentActive?.() || view?.IsSelected ? true : false;
- const childScreenToLocal = () => {
- // need to explicitly trigger an invalidation since we're reading everything from the Dom
- this._forceChildXf;
- this._props.ScreenToLocalTransform();
-
- const dref = this._docRefs.get(doc);
- const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
- if (!scale) return new Transform(0, 0, 0);
-
- return new Transform(-translateX + (dref?.centeringX || 0) * scale,
- -translateY + (dref?.centeringY || 0) * scale, 1)
- .scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore
- };
+ const childScreenToLocal = this.childScreenToLocal(doc, index, calcRowIndex, !!view?.IsContentActive, amCards);
const translateIfSelected = () => {
const indexInRow = index % this._maxRowCount;
const rowIndex = Math.trunc(index / this._maxRowCount);
- const rowCenterIndex = Math.min(this._maxRowCount, sortedDocs.length - rowIndex * this._maxRowCount) / 2;
+ const rowCenterIndex = Math.min(this._maxRowCount, this.sortedDocs.length - rowIndex * this._maxRowCount) / 2;
return (rowCenterIndex - indexInRow) * 100 - 50;
};
const aspect = NumCast(doc.height) / NumCast(doc.width, 1);
@@ -627,33 +610,18 @@ export class CollectionCardView extends CollectionSubView() {
return (
<div
key={doc[Id]}
- className={`card-item${isSelected ? '-active' : anySelected ? '-inactive' : ''}`}
- onPointerUp={action(() => {
- // if a card doc has just moved, or a card is selected and in front, then ignore this event
- if (DocumentView.SelectedDocs().includes(doc) || this._dropped) {
- this._dropped = false;
- } else {
- // otherwise, turn off documentDecorations becase we're in a selection transition and want to avoid artifacts.
- // Turn them back on when the animation has completed and the render and backend structures are in synch
- SnappingManager.SetIsResizing(doc[Id]);
- setTimeout(
- action(() => {
- SnappingManager.SetIsResizing(undefined);
- this._forceChildXf++;
- }),
- 1000
- );
- }
- })}
+ className={`card-item${view?.IsContentActive ? '-active' : this.isAnyChildContentActive() ? '-inactive' : ''}`}
+ onPointerUp={() => this.cardPointerUp(doc)}
style={{
width: this.childPanelWidth(),
height: 'max-content',
- transform: `translateY(${this.calculateTranslateY(this._hoveredNodeIndex === index, isSelected, realIndex, amCards, calcRowIndex)}px)
- translateX(calc(${isSelected ? translateIfSelected() : 0}% + ${this.translateOverflowX(realIndex, amCards)}px))
- rotate(${!isSelected ? this.rotate(amCards, calcRowIndex) : 0}deg)
- scale(${isSelected ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.05 : 1})`,
+ transform: `translateY(${this.calculateTranslateY(!!view?.IsContentActive, index, amCards, calcRowIndex)}px)
+ translateX(calc(${view?.IsContentActive ? translateIfSelected() : 0}% + ${this.translateOverflowX(index, amCards)}px))
+ rotate(${!view?.IsContentActive ? this.rotate(amCards, calcRowIndex) : 0}deg)
+ scale(${view?.IsContentActive ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.1 : 1})`,
}} // prettier-ignore
- onPointerEnter={() => !SnappingManager.IsDragging && this.setHoveredNodeIndex(index)}>
+ onPointerEnter={() => this.setHoveredNodeIndex(index)}
+ onPointerLeave={() => this.setHoveredNodeIndex(-1)}>
{this.displayDoc(doc, childScreenToLocal)}
</div>
);
@@ -680,8 +648,7 @@ export class CollectionCardView extends CollectionSubView() {
...(!isEmpty && { transform: `scale(${1 / this.fitContentScale})` }),
...(!isEmpty && { height: `${100 * this.fitContentScale}%` }),
gridAutoRows: `${100 / this.numRows}%`,
- }}
- onMouseLeave={() => this.setHoveredNodeIndex(-1)}>
+ }}>
{this.renderCards}
</div>
</div>
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index d1304b8f4..e1786d2c9 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -31,17 +31,17 @@ import { ScriptingRepl } from '../ScriptingRepl';
import { UndoStack } from '../UndoStack';
import './CollectionDockingView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
-import { TabHTMLElement } from './TabDocView';
+import { TabDocView, TabHTMLElement } from './TabDocView';
@observer
export class CollectionDockingView extends CollectionSubView() {
- static tabClass: unknown = null;
+ static tabClass?: typeof TabDocView;
/**
* Initialize by assigning the add split method to DocumentView and by
* configuring golden layout to render its documents using the specified React component
* @param ele - typically would be set to TabDocView
*/
- public static Init(ele: unknown) {
+ public static Init(ele: typeof TabDocView) {
this.tabClass = ele;
DocumentView.addSplit = CollectionDockingView.AddSplit;
}
@@ -544,7 +544,7 @@ export class CollectionDockingView extends CollectionSubView() {
tabCreated = (tab: { contentItem: { element: HTMLElement[] } }) => {
this.tabMap.add(tab);
// InitTab is added to the tab's HTMLElement in TabDocView
- const tabdocviewContent = tab.contentItem.element[0]?.firstChild?.firstChild as unknown as TabHTMLElement;
+ const tabdocviewContent = tab.contentItem.element[0]?.firstChild?.firstChild as TabHTMLElement;
tabdocviewContent?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous tabs (ie, when dragging a tab around a new tab is created for the old content)
};
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 5d32482c3..581201a20 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -296,7 +296,7 @@ export function CollectionSubView<X>() {
return false;
}
- protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: (docs: Doc[]) => void) {
+ protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions = {}, completed?: (docs: Doc[]) => void) {
if (e.ctrlKey) {
e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl
return;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index c9e934448..7418d4360 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
import { IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@@ -16,7 +15,6 @@ import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { FieldView } from '../nodes/FieldView';
import { OpenWhere } from '../nodes/OpenWhere';
-import { CollectionCalendarView } from './CollectionCalendarView';
import { CollectionCardView } from './CollectionCardDeckView';
import { CollectionCarousel3DView } from './CollectionCarousel3DView';
import { CollectionCarouselView } from './CollectionCarouselView';
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx
index c17371151..51add85a8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx
@@ -46,7 +46,6 @@ export function InfoState(
gif?: string,
entryFunc?: () => unknown
) {
- // eslint-disable-next-line new-cap
return new infoState(msg, arcs, gif, entryFunc);
}
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 423a2d6ef..2b8908899 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -4,6 +4,7 @@ import { runInAction } from 'mobx';
import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { InkTool } from '../../../fields/InkField';
+import { List } from '../../../fields/List';
import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
import { Gestures } from '../../../pen-gestures/GestureTypes';
@@ -16,7 +17,6 @@ import { UndoManager, undoable } from '../../util/UndoManager';
import { GestureOverlay } from '../GestureOverlay';
import { InkTranscription } from '../InkTranscription';
import { InkingStroke } from '../InkingStroke';
-import { MainView } from '../MainView';
import { PropertiesView } from '../PropertiesView';
import { CollectionFreeFormView } from '../collections/collectionFreeForm';
import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
@@ -40,6 +40,7 @@ import { VideoBox } from '../nodes/VideoBox';
import { WebBox } from '../nodes/WebBox';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
+import { OpenWhere } from '../nodes/OpenWhere';
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function IsNoneSelected() {
@@ -240,31 +241,15 @@ ScriptingGlobals.add(function showFreeform(
['pile', {
checkResult: (doc: Doc) => doc._type_collection == CollectionViewType.Freeform,
setDoc: (doc: Doc, dv: DocumentView) => {
- doc._type_collection = CollectionViewType.Freeform;
const newCol = Docs.Create.CarouselDocument(DocListCast(doc[Doc.LayoutFieldKey(doc)]), {
+ title: doc.title + "_carousel",
_width: 250,
_height: 200,
_layout_fitWidth: false,
_layout_autoHeight: true,
+ childFilters: new List<string>(StrListCast(doc.childFilters))
});
-
-
- const iconMap: { [key: number]: string } = {
- 0: 'star',
- 1: 'heart',
- 2: 'cloud',
- 3: 'bolt'
- };
-
- for (let i=0; i<4; i++){
- if (isAttrFiltered(iconMap[i])){
- newCol[iconMap[i]] = true
- }
- }
-
- newCol && dv.ComponentView?.addDocument?.(newCol);
- DocumentView.showDocument(newCol, { willZoomCentered: true })
-
+ dv._props.addDocTab?.(newCol, OpenWhere.addRight);
},
}],
]);
@@ -300,7 +285,7 @@ ScriptingGlobals.add(function setTagFilter(tag: string, added: boolean, checkRes
added ? Doc.setDocFilter(selected, 'tags', tag, 'check') : Doc.setDocFilter(selected, 'tags', tag, 'remove');
} else {
SnappingManager.PropertiesWidth < 5 && SnappingManager.SetPropertiesWidth(0);
- SnappingManager.SetPropertiesWidth(MainView.Instance.propertiesWidth() < 15 ? 250 : 0);
+ SnappingManager.SetPropertiesWidth(SnappingManager.PropertiesWidth < 15 ? 250 : 0);
PropertiesView.Instance?.CloseAll();
runInAction(() => (PropertiesView.Instance.openFilters = SnappingManager.PropertiesWidth > 5));
}
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index df6e74d85..3dd568fda 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Checkbox } from '@mui/material';
import { Colors, Toggle, ToggleType, Type } from 'browndash-components';
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 23ec42610..5054432a9 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1209,6 +1209,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
public set IsSelected(val) { runInAction(() => { this._selected = val; }); } // prettier-ignore
public get IsSelected() { return this._selected; } // prettier-ignore
+ public get IsContentActive(){ return this._docViewInternal?.isContentActive(); } // prettier-ignore
public get topMost() { return this._props.renderDepth === 0; } // prettier-ignore
public get ContentDiv() { return this._docViewInternal?._contentDiv; } // prettier-ignore
public get ComponentView() { return this._docViewInternal?._componentView; } // prettier-ignore
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 7b652dded..ca783d034 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -6,7 +6,6 @@ import { DateField } from '../../../fields/DateField';
import { Doc, Field, FieldType, Opt } from '../../../fields/Doc';
import { List } from '../../../fields/List';
import { ScriptField } from '../../../fields/ScriptField';
-import { WebField } from '../../../fields/URLField';
import { dropActionType } from '../../util/DropActionTypes';
import { Transform } from '../../util/Transform';
import { PinProps } from '../PinFuncs';
@@ -14,9 +13,9 @@ import { ViewBoxInterface } from '../ViewBoxInterface';
import { DocumentView } from './DocumentView';
import { FocusViewOptions } from './FocusViewOptions';
import { OpenWhere } from './OpenWhere';
+import { WebField } from '../../../fields/URLField';
export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt<number>;
-// eslint-disable-next-line no-use-before-define
export type StyleProviderFuncType = (
doc: Opt<Doc>,
// eslint-disable-next-line no-use-before-define
diff --git a/src/client/views/nodes/RecordingBox/ProgressBar.tsx b/src/client/views/nodes/RecordingBox/ProgressBar.tsx
index 62798bc2f..7e91df7ab 100644
--- a/src/client/views/nodes/RecordingBox/ProgressBar.tsx
+++ b/src/client/views/nodes/RecordingBox/ProgressBar.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable react/no-array-index-key */
-/* eslint-disable react/require-default-props */
import * as React from 'react';
import { useEffect, useState, useRef } from 'react';
import './ProgressBar.scss';
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index 678b7dd0b..d38cb5423 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -1,4 +1,4 @@
-import { Calendar, DateInput, EventClickArg, EventSourceInput } from '@fullcalendar/core';
+import { Calendar, EventClickArg, EventSourceInput } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import multiMonthPlugin from '@fullcalendar/multimonth';
import timeGrid from '@fullcalendar/timegrid';
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 865146d68..037b6315c 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1270,7 +1270,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
@computed get tagsHeight() {
- return this.DocumentView?.().showTags ? Math.max(0, 20 - Math.max(this._props.yPadding ?? 0, NumCast(this.layoutDoc._yMargin))) : 0;
+ return this.DocumentView?.().showTags ? Math.max(0, 20 - Math.max(this._props.yPadding ?? 0, NumCast(this.layoutDoc._yMargin))) * this.ScreenToLocalBoxXf().Scale : 0;
}
@computed get contentScaling() {
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 7a1ab3b4f..74f18cbc8 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -97,9 +97,8 @@ export namespace Field {
});
return script;
}
- export function toString(fieldIn: unknown) {
- const field = fieldIn as FieldType;
- if (typeof field === 'string' || typeof field === 'number' || typeof field === 'boolean') return String(field);
+ export function toString(field: FieldResult<FieldType> | FieldType | undefined) {
+ if (field instanceof Promise || typeof field === 'string' || typeof field === 'number' || typeof field === 'boolean') return String(field);
return field?.[ToString]?.() || '';
}
export function IsField(field: unknown): field is FieldType;
@@ -111,7 +110,7 @@ export namespace Field {
export function Copy(field: unknown) {
return field instanceof ObjectField ? ObjectField.MakeCopy(field) : (field as FieldType);
}
- UndoManager.SetFieldPrinter(toString);
+ UndoManager.SetFieldPrinter((val: unknown) => (IsField(val) ? toString(val) : ''));
}
export type FieldType = number | string | boolean | ObjectField | RefField;
export type Opt<T> = T | undefined;
@@ -463,7 +462,6 @@ export class Doc extends RefField {
});
}
}
-
export namespace Doc {
export let SelectOnLoad: Doc | undefined;
export function SetSelectOnLoad(doc: Doc | undefined) {
diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts
index b3534dde7..8c073c87b 100644
--- a/src/fields/RichTextUtils.ts
+++ b/src/fields/RichTextUtils.ts
@@ -1,4 +1,3 @@
-/* eslint-disable @typescript-eslint/no-namespace */
/* eslint-disable no-await-in-loop */
/* eslint-disable no-use-before-define */
import { AssertionError } from 'assert';
@@ -175,7 +174,6 @@ export namespace RichTextUtils {
const indentMap = new Map<ListGroup, BulletPosition[]>();
let globalOffset = 0;
const nodes: Node[] = [];
- // eslint-disable-next-line no-restricted-syntax
for (const element of structured) {
if (Array.isArray(element)) {
lists.push(element);
@@ -374,11 +372,9 @@ export namespace RichTextUtils {
const marksToStyle = async (nodes: (Node | null)[]): Promise<docsV1.Schema$Request[]> => {
const requests: docsV1.Schema$Request[] = [];
let position = 1;
- // eslint-disable-next-line no-restricted-syntax
for (const node of nodes) {
if (node === null) {
position += 2;
- // eslint-disable-next-line no-continue
continue;
}
const { marks, attrs, nodeSize } = node;
@@ -390,9 +386,7 @@ export namespace RichTextUtils {
};
let mark: Mark;
const markMap = BuildMarkMap(marks);
- // eslint-disable-next-line no-restricted-syntax
for (const markName of Object.keys(schema.marks)) {
- // eslint-disable-next-line no-cond-assign
if (ignored.includes(markName) || !(mark = markMap[markName])) {
continue;
}
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index 1e25a8a27..effe94219 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -61,27 +61,6 @@ export namespace WebSocket {
Database.Instance.getDocuments(ids, callback);
}
- const pendingOps = new Map<string, { diff: Diff; socket: Socket }[]>();
-
- function dispatchNextOp(id: string): unknown {
- const next = pendingOps.get(id)?.shift();
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- const nextOp = (res: boolean) => dispatchNextOp(id);
- if (next) {
- const { diff, socket } = next;
- // ideally, we'd call the Database update method for all actions, but for now we handle list insertion/removal on our own
- switch (diff.diff.$addToSet ? 'add' : diff.diff.$remFromSet ? 'rem' : 'set') {
- case 'add': return GetRefFieldLocal(id, (result) => addToListField(socket, diff, result, nextOp)); // prettier-ignore
- case 'rem': return GetRefFieldLocal(id, (result) => remFromListField(socket, diff, result, nextOp)); // prettier-ignore
- default: return Database.Instance.update(id, diff.diff,
- () => nextOp(socket.broadcast.emit(MessageStore.UpdateField.Message, diff)),
- false
- ); // prettier-ignore
- }
- }
- return !pendingOps.get(id)?.length && pendingOps.delete(id);
- }
-
function addToListField(socket: Socket, diff: Diff, listDoc: serializedDoctype | undefined, cb: (res: boolean) => void): void {
const $addToSet = diff.diff.$addToSet as serializedFieldsType;
const updatefield = Array.from(Object.keys($addToSet ?? {}))[0];
@@ -181,6 +160,27 @@ export namespace WebSocket {
} else cb(false);
}
+ const pendingOps = new Map<string, { diff: Diff; socket: Socket }[]>();
+
+ function dispatchNextOp(id: string): unknown {
+ const next = pendingOps.get(id)?.shift();
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const nextOp = (res: boolean) => dispatchNextOp(id);
+ if (next) {
+ const { diff, socket } = next;
+ // ideally, we'd call the Database update method for all actions, but for now we handle list insertion/removal on our own
+ switch (diff.diff.$addToSet ? 'add' : diff.diff.$remFromSet ? 'rem' : 'set') {
+ case 'add': return GetRefFieldLocal(id, (result) => addToListField(socket, diff, result, nextOp)); // prettier-ignore
+ case 'rem': return GetRefFieldLocal(id, (result) => remFromListField(socket, diff, result, nextOp)); // prettier-ignore
+ default: return Database.Instance.update(id, diff.diff,
+ () => nextOp(socket.broadcast.emit(MessageStore.UpdateField.Message, diff)),
+ false
+ ); // prettier-ignore
+ }
+ }
+ return !pendingOps.get(id)?.length && pendingOps.delete(id);
+ }
+
function UpdateField(socket: Socket, diff: Diff) {
const curUser = socketMap.get(socket);
if (curUser) {