aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/FilterPanel.tsx2
-rw-r--r--src/client/views/GestureOverlay.tsx171
-rw-r--r--src/client/views/GlobalKeyHandler.ts9
-rw-r--r--src/client/views/InkingStroke.tsx3
-rw-r--r--src/client/views/LightboxView.tsx4
-rw-r--r--src/client/views/MarqueeAnnotator.tsx3
-rw-r--r--src/client/views/PinFuncs.ts23
-rw-r--r--src/client/views/SidebarAnnos.tsx4
-rw-r--r--src/client/views/StyleProp.ts4
-rw-r--r--src/client/views/StyleProvider.tsx9
-rw-r--r--src/client/views/StyleProviderQuiz.tsx2
-rw-r--r--src/client/views/ViewBoxInterface.ts2
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx66
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.tsx43
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx28
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx5
-rw-r--r--src/client/views/collections/CollectionSubView.tsx17
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx4
-rw-r--r--src/client/views/collections/FlashcardPracticeUI.tsx6
-rw-r--r--src/client/views/collections/TabDocView.tsx1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx94
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx2
-rw-r--r--src/client/views/collections/collectionSchema/SchemaRowBox.tsx2
-rw-r--r--src/client/views/global/globalScripts.ts134
-rw-r--r--src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx6
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx5
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx21
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx6
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx35
-rw-r--r--src/client/views/nodes/DocumentView.tsx84
-rw-r--r--src/client/views/nodes/EquationBox.tsx2
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.scss7
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx190
-rw-r--r--src/client/views/nodes/ImageBox.tsx10
-rw-r--r--src/client/views/nodes/LabelBox.scss1
-rw-r--r--src/client/views/nodes/LabelBox.tsx168
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx2
-rw-r--r--src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx5
-rw-r--r--src/client/views/nodes/PDFBox.tsx2
-rw-r--r--src/client/views/nodes/VideoBox.tsx2
-rw-r--r--src/client/views/nodes/WebBox.tsx13
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx273
-rw-r--r--src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts4
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx82
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts2
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx57
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx23
-rw-r--r--src/client/views/pdf/PDFViewer.tsx2
-rw-r--r--src/client/views/smartdraw/SmartDrawHandler.tsx12
52 files changed, 905 insertions, 761 deletions
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 11425e477..99738052d 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -102,7 +102,7 @@ const HotKeyIconButton: React.FC<HotKeyButtonProps> = observer(({ hotKey /*, sel
return (
<div
- className={`filterHotKey-button`}
+ className="filterHotKey-button"
onClick={e => {
e.stopPropagation();
state.startEditing();
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index afeecaa63..2d6cd03e0 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -2,9 +2,9 @@ import * as fitCurve from 'fit-curve';
import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { returnEmptyFilter, returnEmptyString, returnFalse, setupMoveUpEvents } from '../../ClientUtils';
+import { setupMoveUpEvents } from '../../ClientUtils';
import { emptyFunction, intersectRect } from '../../Utils';
-import { Doc, Opt, returnEmptyDoclist } from '../../fields/Doc';
+import { Doc } from '../../fields/Doc';
import { InkData, InkField, InkTool } from '../../fields/InkField';
import { NumCast } from '../../fields/Types';
import { Gestures } from '../../pen-gestures/GestureTypes';
@@ -14,27 +14,25 @@ import { DocumentType } from '../documents/DocumentTypes';
import { Docs } from '../documents/Documents';
import { InteractionUtils } from '../util/InteractionUtils';
import { ScriptingGlobals } from '../util/ScriptingGlobals';
-import { Transform } from '../util/Transform';
+import { SnappingManager } from '../util/SnappingManager';
import { undoable } from '../util/UndoManager';
import './GestureOverlay.scss';
import { InkingStroke } from './InkingStroke';
import { ObservableReactComponent } from './ObservableReactComponent';
-import { returnEmptyDocViewList } from './StyleProvider';
import { CollectionFreeFormView } from './collections/collectionFreeForm';
import {
- ActiveArrowEnd,
- ActiveArrowScale,
- ActiveArrowStart,
- ActiveDash,
- ActiveFillColor,
- ActiveInkBezierApprox,
+ ActiveInkArrowEnd,
+ ActiveInkArrowScale,
+ ActiveInkArrowStart,
ActiveInkColor,
+ ActiveInkDash,
+ ActiveInkFillColor,
ActiveInkWidth,
DocumentView,
- SetActiveArrowStart,
- SetActiveDash,
- SetActiveFillColor,
+ SetActiveInkArrowStart,
SetActiveInkColor,
+ SetActiveInkDash,
+ SetActiveInkFillColor,
SetActiveInkWidth,
} from './nodes/DocumentView';
export enum ToolglassTools {
@@ -57,18 +55,14 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
// eslint-disable-next-line no-use-before-define
static Instances: GestureOverlay[] = [];
- @observable public InkShape: Opt<Gestures> = undefined;
@observable public SavedColor?: string = undefined;
@observable public SavedWidth?: number = undefined;
@observable public Tool: ToolglassTools = ToolglassTools.None;
- @observable public KeepPrimitiveMode = false; // for whether primitive selection enters a one-shot or persistent mode
@observable private _thumbX?: number = undefined;
@observable private _thumbY?: number = undefined;
@observable private _pointerY?: number = undefined;
@observable private _points: { X: number; Y: number }[] = [];
- @observable private _strokes: InkData[] = [];
- @observable private _palette?: JSX.Element = undefined;
@observable private _clipboardDoc?: JSX.Element = undefined;
@computed private get height(): number {
@@ -95,8 +89,9 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
}
@action
onPointerDown = (e: React.PointerEvent) => {
+ (document.activeElement as HTMLElement)?.blur();
if (!(e.target as HTMLElement)?.className?.toString().startsWith('lm_')) {
- if ([InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (Doc.ActiveTool === InkTool.Ink) {
this._points.push({ X: e.clientX, Y: e.clientY });
setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction);
}
@@ -122,13 +117,9 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
};
@action primCreated() {
- if (!this.KeepPrimitiveMode) {
- this.InkShape = undefined;
- // get out of ink mode after each stroke=
- // if (Doc.ActiveTool === InkTool.Highlighter && GestureOverlay.Instance.SavedColor) SetActiveInkColor(GestureOverlay.Instance.SavedColor);
+ if (!SnappingManager.KeepGestureMode) {
+ SnappingManager.SetInkShape(undefined);
Doc.ActiveTool = InkTool.None;
- // SetActiveArrowStart('none');
- // SetActiveArrowEnd('none');
}
}
/**
@@ -244,15 +235,16 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
this.dispatchGesture(Gestures.Stroke);
};
@action
- onPointerUp = () => {
+ onPointerUp = (e: PointerEvent) => {
const ffView = DocumentView.DownDocView?.ComponentView instanceof CollectionFreeFormView && DocumentView.DownDocView.ComponentView;
+ const downView = DocumentView.DownDocView;
DocumentView.DownDocView = undefined;
if (this._points.length > 1) {
const B = this.svgBounds;
const points = this._points.map(p => ({ X: p.X - B.left, Y: p.Y - B.top }));
const { Name, Score } =
- (this.InkShape
- ? new Result(this.InkShape, 1, Date.now)
+ (SnappingManager.InkShape
+ ? new Result(SnappingManager.InkShape, 1, Date.now)
: Doc.UserDoc().recognizeGestures && points.length > 2
? GestureUtils.GestureRecognizer.Recognize([points])
: undefined) ??
@@ -286,7 +278,11 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
this.dryInk();
}
}
+ } else {
+ (downView?.ComponentView as CollectionFreeFormView)?._marqueeViewRef?.current?.setPreviewCursor?.(this._points[0].X, this._points[0].Y, false, false, undefined);
+ e.preventDefault();
}
+ this.primCreated();
this._points.length = 0;
};
/**
@@ -552,97 +548,38 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
B.bottom += width / 2;
B.width += width;
B.height += width;
- const fillColor = ActiveFillColor();
+ const fillColor = ActiveInkFillColor();
const strokeColor = fillColor && fillColor !== 'transparent' ? fillColor : ActiveInkColor();
return [
this.props.children,
- this._palette,
- [
- this._strokes.map((l, i) => {
- const b = { left: -20000, right: 20000, top: -20000, bottom: 20000, width: 40000, height: 40000 }; // this.getBounds(l, true);
- return (
- <svg key={i} width={b.width} height={b.height} style={{ top: 0, left: 0, transform: `translate(${b.left}px, ${b.top}px)`, pointerEvents: 'none', position: 'absolute', zIndex: 30000, overflow: 'visible' }}>
- {InteractionUtils.CreatePolyline(
- l,
- b.left,
- b.top,
- strokeColor,
- width,
- width,
- 'miter',
- 'round',
- ActiveInkBezierApprox(),
- 'none' /* ActiveFillColor() */,
- ActiveArrowStart(),
- ActiveArrowEnd(),
- ActiveArrowScale(),
- ActiveDash(),
- 1,
- 1,
- this.InkShape as Gestures,
- 'none',
- 1.0,
- false
- )}
- </svg>
- );
- }),
- this._points.length <= 1 ? null : (
- <svg key="svg" width={B.width} height={B.height} style={{ top: 0, left: 0, transform: `translate(${B.left}px, ${B.top}px)`, pointerEvents: 'none', position: 'absolute', zIndex: 30000, overflow: 'visible' }}>
- {InteractionUtils.CreatePolyline(
- this._points.map(p => ({ X: p.X - (rect?.x || 0), Y: p.Y - (rect?.y || 0) })),
- B.left,
- B.top,
- ActiveInkColor(),
- width,
- width,
- 'miter',
- 'round',
- '',
- 'none' /* ActiveFillColor() */,
- ActiveArrowStart(),
- ActiveArrowEnd(),
- ActiveArrowScale(),
- ActiveDash(),
- 1,
- 1,
- this.InkShape as Gestures,
- 'none',
- 1.0,
- false
- )}
- </svg>
- ),
- ],
+ this._points.length <= 1 ? null : (
+ <svg key="svg" width={B.width} height={B.height} style={{ top: 0, left: 0, transform: `translate(${B.left}px, ${B.top}px)`, pointerEvents: 'none', position: 'absolute', zIndex: 30000, overflow: 'visible' }}>
+ {InteractionUtils.CreatePolyline(
+ this._points.map(p => ({ X: p.X - (rect?.x || 0), Y: p.Y - (rect?.y || 0) })),
+ B.left,
+ B.top,
+ strokeColor,
+ width,
+ width,
+ 'miter',
+ 'round',
+ '',
+ 'none' /* ActiveFillColor() */,
+ ActiveInkArrowStart(),
+ ActiveInkArrowEnd(),
+ ActiveInkArrowScale(),
+ ActiveInkDash(),
+ 1,
+ 1,
+ SnappingManager.InkShape,
+ 'none',
+ 1.0,
+ false
+ )}
+ </svg>
+ ),
];
}
- screenToLocalTransform = () => new Transform(-(this._thumbX ?? 0), -(this._thumbY ?? 0) + this.height, 1);
- return300 = () => 300;
- @action
- public openFloatingDoc = (doc: Doc) => {
- this._clipboardDoc = (
- <DocumentView
- Document={doc}
- addDocument={undefined}
- addDocTab={returnFalse}
- pinToPres={emptyFunction}
- removeDocument={undefined}
- ScreenToLocalTransform={this.screenToLocalTransform}
- PanelWidth={this.return300}
- PanelHeight={this.return300}
- isDocumentActive={returnFalse}
- isContentActive={returnFalse}
- renderDepth={0}
- styleProvider={returnEmptyString}
- containerViewPath={returnEmptyDocViewList}
- focus={emptyFunction}
- whenChildContentsActiveChanged={emptyFunction}
- childFiltersByRanges={returnEmptyFilter}
- childFilters={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- />
- );
- };
@action
public closeFloatingDoc = () => {
@@ -689,10 +626,10 @@ ScriptingGlobals.add(function setPen(width: string, color: string, fill: string,
SetActiveInkColor(color);
GestureOverlay.Instance.SavedWidth = ActiveInkWidth();
SetActiveInkWidth(width);
- SetActiveFillColor(fill);
- SetActiveArrowStart(arrowStart);
- SetActiveArrowStart(arrowEnd);
- SetActiveDash(dash);
+ SetActiveInkFillColor(fill);
+ SetActiveInkArrowStart(arrowStart);
+ SetActiveInkArrowStart(arrowEnd);
+ SetActiveInkDash(dash);
});
});
// eslint-disable-next-line prefer-arrow-callback
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index d7d8e9506..f16338361 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -2,7 +2,7 @@ import { random } from 'lodash';
import { action } from 'mobx';
import { Doc, DocListCast } from '../../fields/Doc';
import { Id } from '../../fields/FieldSymbols';
-import { InkTool } from '../../fields/InkField';
+import { InkInkTool, InkTool } from '../../fields/InkField';
import { ScriptField } from '../../fields/ScriptField';
import { Cast, PromiseValue } from '../../fields/Types';
import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
@@ -280,10 +280,10 @@ export class KeyManager {
}
break;
case 'e':
- Doc.ActiveTool = [InkTool.StrokeEraser, InkTool.SegmentEraser, InkTool.RadiusEraser].includes(Doc.ActiveTool) ? InkTool.None : InkTool.StrokeEraser;
+ Doc.ActiveTool = Doc.ActiveTool === InkTool.Eraser ? InkTool.None : InkTool.Eraser;
break;
case 'p':
- Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen;
+ Doc.ActiveTool = Doc.ActiveTool === InkTool.Ink ? InkTool.None : InkTool.Ink;
break;
case 'r':
preventDefault = false;
@@ -378,7 +378,8 @@ export class KeyManager {
UndoManager.Redo();
break;
case 'p':
- Doc.ActiveTool = InkTool.Write;
+ Doc.ActiveInk = InkInkTool.Write;
+ Doc.ActiveTool = InkTool.Ink;
break;
default:
}
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 270266a94..5199eb02b 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -470,14 +470,13 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>()
className="inkStroke"
style={{
transform: isInkMask ? `rotate(-${NumCast(this._props.LocalRotation?.() ?? 0)}deg) translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined,
- // mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? 'multiply' : 'unset',
cursor: this._props.isSelected() ? 'default' : undefined,
}}
{...interactions}>
{clickableLine(this.onPointerDown, isInkMask)}
{isInkMask ? null : inkLine}
</svg>
- {!closed || this.dataDoc[this.fieldKey + '_showLabel'] === false || (!RTFCast(this.dataDoc.text)?.Text && !this.dataDoc[this.fieldKey + '_showLabel'] && (!this._props.isSelected() || Doc.UserDoc().activeInkHideTextLabels)) ? null : (
+ {!closed || this.dataDoc[this.fieldKey + '_showLabel'] === false || (!RTFCast(this.dataDoc.text)?.Text && !this.dataDoc[this.fieldKey + '_showLabel'] && (!this._props.isSelected() || Doc.UserDoc().activeHideTextLabels)) ? null : (
<div
className="inkStroke-text"
style={{
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index a543b4875..3a8a38073 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -214,7 +214,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
// if (this._showPalette === false) AnnotationPalette.Instance.resetPalette(true);
};
togglePen = () => {
- Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen;
+ Doc.ActiveTool = Doc.ActiveTool === InkTool.Ink ? InkTool.None : InkTool.Ink;
};
toggleExplore = () => SnappingManager.SetExploreMode(!SnappingManager.ExploreMode);
@@ -332,7 +332,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
{toggleBtn('lightboxView-navBtn', 'toggle reading view', BoolCast(this._doc?._layout_fitWidth), 'book-open', 'book', this.toggleFitWidth)}
{toggleBtn('lightboxView-tabBtn', 'open document in a tab', false, 'file-export', '', this.downloadDoc)}
{toggleBtn('lightboxView-paletteBtn', 'toggle annotation palette', this._showPalette === true, 'palette', '', this.togglePalette)}
- {toggleBtn('lightboxView-penBtn', 'toggle pen annotation', Doc.ActiveTool === InkTool.Pen, 'pen', '', this.togglePen)}
+ {toggleBtn('lightboxView-penBtn', 'toggle pen annotation', Doc.ActiveTool === InkTool.Ink, 'pen', '', this.togglePen)}
{toggleBtn('lightboxView-exploreBtn', 'toggle navigate only mode', SnappingManager.ExploreMode, 'globe-americas', '', this.toggleExplore)}
</div>
);
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 7266875c5..fa1123a2d 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -34,7 +34,7 @@ export interface MarqueeAnnotatorProps {
getPageFromScroll?: (top: number) => number;
finishMarquee: (x?: number, y?: number) => void;
anchorMenuClick?: () => undefined | ((anchor: Doc) => void);
- anchorMenuFlashcard?: () => Promise<String>;
+ anchorMenuFlashcard?: () => Promise<string>;
anchorMenuCrop?: (anchor: Doc | undefined, addCrop: boolean) => Doc | undefined;
highlightDragSrcColor?: string;
}
@@ -220,7 +220,6 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
e.preventDefault();
e.stopPropagation();
let cropRegion: Doc | undefined;
- // eslint-disable-next-line no-return-assign
const sourceAnchorCreator = () => (cropRegion = this.highlight('', true, undefined, true)); // hyperlink color
const targetCreator = (/* annotationOn: Doc | undefined */) => this.props.anchorMenuCrop!(cropRegion, false)!;
DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docView(), sourceAnchorCreator, targetCreator), e.pageX, e.pageY, {
diff --git a/src/client/views/PinFuncs.ts b/src/client/views/PinFuncs.ts
index 430455644..ab02c2d07 100644
--- a/src/client/views/PinFuncs.ts
+++ b/src/client/views/PinFuncs.ts
@@ -1,4 +1,4 @@
-import { Doc, DocListCast } from '../../fields/Doc';
+import { Doc, DocListCast, Field } from '../../fields/Doc';
import { DocData } from '../../fields/DocSymbols';
import { Copy, Id } from '../../fields/FieldSymbols';
import { List } from '../../fields/List';
@@ -16,7 +16,7 @@ export interface pinDataTypes {
scrollable?: boolean;
dataviz?: number[];
pannable?: boolean;
- type_collection?: boolean;
+ collectionType?: boolean;
inkable?: boolean;
filters?: boolean;
pivot?: boolean;
@@ -39,9 +39,14 @@ export interface PinProps {
pinData?: pinDataTypes;
}
-/// copies values from the targetDoc (which is the prototype of the pinDoc) to
-/// reserved fields on the pinDoc so that those values can be restored to the
-/// target doc when navigating to it.
+/**
+ * copies values from the targetDoc (which is the prototype of the pinDoc) to
+ * reserved fields on the pinDoc so that those values can be restored to the
+ * target doc when navigating to it.
+ * @param pinDoc Doc that will store pinned metadata
+ * @param pinProps description of props to pin
+ * @param targetDoc Doc that is being pinned
+ */
export function PinDocView(pinDocIn: Doc, pinProps: PinProps, targetDoc: Doc) {
const pinDoc = pinDocIn;
pinDoc.presentation = true;
@@ -60,7 +65,7 @@ export function PinDocView(pinDocIn: Doc, pinProps: PinProps, targetDoc: Doc) {
pinProps.pinData.scrollable ||
pinProps.pinData.temporal ||
pinProps.pinData.pannable ||
- pinProps.pinData.type_collection ||
+ pinProps.pinData.collectionType ||
pinProps.pinData.clippable ||
pinProps.pinData.datarange ||
pinProps.pinData.dataview ||
@@ -69,7 +74,7 @@ export function PinDocView(pinDocIn: Doc, pinProps: PinProps, targetDoc: Doc) {
const fkey = Doc.LayoutFieldKey(targetDoc);
if (pinProps.pinData.dataview) {
pinDoc.config_usePath = targetDoc[fkey + '_usePath'];
- pinDoc.config_data = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data;
+ pinDoc.config_data = Field.Copy(targetDoc[fkey]);
}
if (pinProps.pinData.dataannos) {
const fieldKey = Doc.LayoutFieldKey(targetDoc);
@@ -113,8 +118,8 @@ export function PinDocView(pinDocIn: Doc, pinProps: PinProps, targetDoc: Doc) {
})
)
);
- if (pinProps.pinData.type_collection) pinDoc.config_viewType = targetDoc._type_collection;
- if (pinProps.pinData.filters) pinDoc.config_docFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField);
+ if (pinProps.pinData.collectionType) pinDoc.config_type_collection = targetDoc._type_collection;
+ if (pinProps.pinData.filters) pinDoc.config_docFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField) ?? new List<string>();
if (pinProps.pinData.pivot) pinDoc.config_pivotField = targetDoc._pivotField;
if (pinProps.pinData.pannable) {
pinDoc.config_panX = NumCast(targetDoc._freeform_panX);
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 1f3ad8444..87076bf65 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -78,8 +78,8 @@ export class SidebarAnnos extends ObservableReactComponent<FieldViewProps & Extr
_height: 50,
_layout_fitWidth: true,
_layout_autoHeight: true,
- _text_fontSize: StrCast(Doc.UserDoc().fontSize),
- _text_fontFamily: StrCast(Doc.UserDoc().fontFamily),
+ text_fontSize: StrCast(Doc.UserDoc().fontSize),
+ text_fontFamily: StrCast(Doc.UserDoc().fontFamily),
});
Doc.SetSelectOnLoad(target);
FormattedTextBox.DontSelectInitialText = true;
diff --git a/src/client/views/StyleProp.ts b/src/client/views/StyleProp.ts
index 44d3bf757..56367e70b 100644
--- a/src/client/views/StyleProp.ts
+++ b/src/client/views/StyleProp.ts
@@ -19,7 +19,9 @@ export enum StyleProp {
FontColor = 'fontColor', // color o tet
FontSize = 'fontSize', // size of text font
FontFamily = 'fontFamily', // font family of text
- FontWeight = 'fontWeight', // font weight of text
+ FontWeight = 'fontWeight', // font weight of text (eg bold)
+ FontStyle = 'fontStyle', // font style of text (eg italic)
+ FontDecoration = 'fontDecoration', // text decoration of text (eg underline)
Highlighting = 'highlighting', // border highlighting
ContextMenuItems = 'contextMenuItems', // menu items to add to context menu
AnchorMenuItems = 'anchorMenuItems',
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 8859f6464..3a5f57908 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -25,6 +25,7 @@ import { styleProviderQuiz } from './StyleProviderQuiz';
import { StyleProp } from './StyleProp';
import './StyleProvider.scss';
import { TagsView } from './TagsView';
+import { InkInkTool } from '../../fields/InkField';
function toggleLockedPosition(doc: Doc) {
UndoManager.RunInBatch(() => Doc.toggleLockedPosition(doc), 'toggleBackground');
@@ -171,7 +172,9 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
case StyleProp.FontSize: return StrCast(doc?.[fieldKey + 'fontSize'], StrCast(Doc.UserDoc().fontSize));
case StyleProp.FontFamily: return StrCast(doc?.[fieldKey + 'fontFamily'], StrCast(Doc.UserDoc().fontFamily));
case StyleProp.FontWeight: return StrCast(doc?.[fieldKey + 'fontWeight'], StrCast(Doc.UserDoc().fontWeight));
- case StyleProp.FillColor: return StrCast(doc?._fillColor, StrCast(doc?.fillColor, StrCast(doc?.backgroundColor, 'transparent')));
+ case StyleProp.FontStyle: return StrCast(doc?.[fieldKey + 'fontStyle'], StrCast(Doc.UserDoc().fontStyle));
+ case StyleProp.FontDecoration:return StrCast(doc?.[fieldKey + 'fontDecoration'], StrCast(Doc.UserDoc().fontDecoration));
+ case StyleProp.FillColor: return StrCast(doc?._fillColor, StrCast(doc?.fillColor, StrCast(doc?.backgroundColor, StrCast(Doc.UserDoc()[Doc.ActiveInk === InkInkTool.Highlight ? "inkHighlighterColor": "inkFillColor"], 'transparent'))));
case StyleProp.ShowCaption: return hideCaptions || doc?._type_collection === CollectionViewType.Carousel ? undefined: StrCast(doc?._layout_showCaption);
case StyleProp.TitleHeight: return Math.min(4,(docView?.().screenToViewTransform().Scale ?? 1)) * NumCast(Doc.UserDoc().headerHeight,30);
case StyleProp.ShowTitle: return (
@@ -251,7 +254,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
case DocumentType.PRESELEMENT: docColor = docColor || ""; break;
case DocumentType.PRES: docColor = docColor || 'transparent'; break;
case DocumentType.FONTICON: docColor = boxBackground ? undefined : docColor || Colors.DARK_GRAY; break;
- case DocumentType.RTF: docColor = docColor || Colors.LIGHT_GRAY; break;
+ case DocumentType.RTF: docColor = docColor || StrCast(Doc.UserDoc().textBackgroundColor, Colors.LIGHT_GRAY); break;
case DocumentType.LINK: docColor = (isAnchor ? docColor : undefined); break;
case DocumentType.INK: docColor = doc?.stroke_isInkMask ? 'rgba(0,0,0,0.7)' : undefined; break;
case DocumentType.EQUATION: docColor = docColor || 'transparent'; break;
@@ -313,7 +316,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
? undefined // if it's a background & has a cluster color, make the shadow spread really big
: fieldKey.includes('_inline') // if doc is an inline document in a text box
? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0vw 0vw 0.1vw')}`
- : DocCast(doc.embedContainer)?.type === DocumentType.RTF && !isInk() // if doc is embedded in a text document (but not an inline)
+ :doc.rootDocument !== doc.embedContainer && DocCast(doc.embedContainer)?.type === DocumentType.RTF && !isInk() // if doc is embedded in a text document (but not an inline) and this isn't a simple text template (where the layoutDoc's rootDocument is its embed container)
? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}`
: StrCast(doc.layout_boxShadow, '');
}
diff --git a/src/client/views/StyleProviderQuiz.tsx b/src/client/views/StyleProviderQuiz.tsx
index 1f2ad1485..f07a2c803 100644
--- a/src/client/views/StyleProviderQuiz.tsx
+++ b/src/client/views/StyleProviderQuiz.tsx
@@ -66,7 +66,7 @@ export namespace styleProviderQuiz {
newCol.zIndex = 1000;
newCol.forceActive = true;
newCol.quiz = text;
- newCol[DocData].textTransform = 'none';
+ newCol[DocData][Doc.LayoutFieldKey(newCol) + '_transform'] = 'none';
Doc.AddDocToList(img.Document, '_quizBoxes', newCol);
img.addDocument(newCol);
// img._loading = false;
diff --git a/src/client/views/ViewBoxInterface.ts b/src/client/views/ViewBoxInterface.ts
index f66f6062e..b7980d74e 100644
--- a/src/client/views/ViewBoxInterface.ts
+++ b/src/client/views/ViewBoxInterface.ts
@@ -24,7 +24,7 @@ export abstract class ViewBoxInterface<P> extends ObservableReactComponent<React
promoteCollection?: () => void; // moves contents of collection to parent
updateIcon?: (usePanelDimensions?: boolean) => Promise<void>; // updates the icon representation of the document
getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
- restoreView?: (viewSpec: Doc) => boolean;
+ restoreView?: (viewSpec: Doc) => boolean; // DEPRECATED: do not use, it will go away. see PresBox.restoreTargetDocView
scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: FocusViewOptions) => Opt<number>; // returns the duration of the focus
brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms)
getView?: (doc: Doc, options: FocusViewOptions) => Promise<Opt<DocumentView>>; // returns a nested DocumentView for the specified doc or undefined
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index b86dad9d7..0ba6b679c 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -13,18 +13,20 @@ import { BoolCast, DateCast, DocCast, NumCast, RTFCast, ScriptCast, StrCast } fr
import { URLField } from '../../../fields/URLField';
import { gptImageLabel } from '../../apis/gpt/GPT';
import { DocumentType } from '../../documents/DocumentTypes';
+import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
import { dropActionType } from '../../util/DropActionTypes';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoable } from '../../util/UndoManager';
+import { PinDocView } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { TagItem } from '../TagsView';
import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
+import { FocusViewOptions } from '../nodes/FocusViewOptions';
import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
import './CollectionCardDeckView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
-import { FocusViewOptions } from '../nodes/FocusViewOptions';
enum cardSortings {
Time = 'time',
@@ -49,14 +51,13 @@ export class CollectionCardView extends CollectionSubView() {
private _textToDoc = new Map<string, Doc>();
private _oldWheel: HTMLElement | null = null;
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)
- private _clickScript = () => ScriptField.MakeScript('scriptContext._curDoc=this', { scriptContext: 'any' })!;
+ private _setCurDocScript = () => ScriptField.MakeScript('scriptContext.layoutDoc._card_curDoc=this', { scriptContext: 'any' })!;
@observable _forceChildXf = 0;
@observable _hoveredNodeIndex = -1;
@observable _docRefs = new ObservableMap<Doc, DocumentView>();
@observable _maxRowCount = 10;
@observable _docDraggedIndex: number = -1;
- @observable _curDoc: Doc | undefined = undefined;
constructor(props: SubCollectionViewProps) {
super(props);
@@ -163,10 +164,10 @@ export class CollectionCardView extends CollectionSubView() {
/**
* When in quiz mode, randomly selects a document
*/
- quizMode = action(() => {
+ quizMode = () => {
const randomIndex = Math.floor(Math.random() * this.childDocs.length);
- this._curDoc = this.childDocs[randomIndex];
- });
+ this.layoutDoc._card_curDoc = this.childDocs[randomIndex];
+ };
setHoveredNodeIndex = action((index: number) => {
if (!SnappingManager.IsDragging) this._hoveredNodeIndex = index;
@@ -317,7 +318,7 @@ export class CollectionCardView extends CollectionSubView() {
(doc: Doc) => () =>
this._props.isContentActive?.() === false
? false
- : this._props.isDocumentActive?.() && this._curDoc === doc
+ : this._props.isDocumentActive?.() && this.curDoc() === doc
? true
: this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
? false
@@ -345,7 +346,7 @@ export class CollectionCardView extends CollectionSubView() {
scriptContext={this}
focus={this.focus}
onDoubleClickScript={this.onChildDoubleClick}
- onClickScript={this._curDoc === doc ? undefined : this._clickScript}
+ onClickScript={this.curDoc() === doc ? undefined : this._setCurDocScript}
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)}
@@ -570,8 +571,8 @@ export class CollectionCardView extends CollectionSubView() {
* @param doc doc that will be animated away from center focus
*/
releaseCurDoc = action(() => {
- const selDoc = this._curDoc;
- this._curDoc = undefined;
+ const selDoc = this.curDoc();
+ this.layoutDoc._card_curDoc = undefined;
const cardDocView = DocumentView.getDocumentView(selDoc, this.DocumentView?.());
if (cardDocView && selDoc) {
DocumentView.DeselectView(cardDocView);
@@ -588,7 +589,7 @@ export class CollectionCardView extends CollectionSubView() {
* turns off the _dropped flag at the end of a drag/drop, or releases the focused Doc if a different Doc is clicked
*/
cardPointerUp = action((doc: Doc) => {
- if (this._curDoc === doc || this._dropped) {
+ if (this.curDoc() === doc || this._dropped) {
this._dropped = false;
} else {
this.releaseCurDoc(); // NOTE: the onClick script for the card will select the new card (ie, 'doc')
@@ -596,27 +597,36 @@ export class CollectionCardView extends CollectionSubView() {
});
focus = action((anchor: Doc, options: FocusViewOptions): Opt<number> => {
- const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]);
- if (anchor.type !== DocumentType.CONFIG && !docs.includes(anchor)) return undefined;
- options.didMove = true;
- const target = DocCast(anchor.annotationOn) ?? anchor;
- const index = docs.indexOf(target);
- index !== -1 && (this._curDoc = target);
+ const docs = DocListCast(this.Document[this.fieldKey]);
+ if (anchor.type === DocumentType.CONFIG || docs.includes(anchor)) {
+ const foundDoc = DocCast(
+ anchor.config_card_curDoc,
+ docs.find(doc => doc === DocCast(anchor.annotationOn, anchor))
+ );
+ options.didMove = foundDoc !== this.curDoc() ? true : false;
+ options.didMove && (this.layoutDoc._card_curDoc = foundDoc);
+ }
return undefined;
});
+ getAnchor = (addAsAnnotation: boolean) => {
+ const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document, config_card_curDoc: this.curDoc() });
+ PinDocView(anchor, { pinData: { collectionType: true, filters: true } }, this.Document);
+ addAsAnnotation && Doc.AddDocToList(this.dataDoc, this.fieldKey + '_annotations', anchor); // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered
+ return anchor;
+ };
+ addDocTab = this.addLinkedDocTab;
/**
* Actually renders all the cards
*/
@computed get renderCards() {
- console.log('CHILDPw = ' + this.childPanelWidth());
// Map sorted documents to their rendered components
return this.sortedDocs.map((doc, index) => {
const cardsInRow = this.cardsInRowThatIncludesCardIndex(index);
- const childScreenToLocal = this.childScreenToLocal(doc, index, doc === this._curDoc);
+ const childScreenToLocal = this.childScreenToLocal(doc, index, doc === this.curDoc());
- const translateToCenterIfActive = () => (doc === this._curDoc ? (cardsInRow / 2 - (index % this._maxRowCount)) * 100 - 50 : 0);
+ const translateToCenterIfActive = () => (doc === this.curDoc() ? (cardsInRow / 2 - (index % this._maxRowCount)) * 100 - 50 : 0);
const aspect = NumCast(doc.height) / NumCast(doc.width, 1);
const vscale = Math.max(1,Math.min((this._props.PanelHeight() * 0.95 * this.fitContentScale * this.nativeScaling) / (aspect * this.childPanelWidth()),
@@ -625,15 +635,15 @@ export class CollectionCardView extends CollectionSubView() {
return (
<div
key={doc[Id]}
- className={`card-item${doc === this._curDoc ? '-active' : this.isAnyChildContentActive() ? '-inactive' : ''}`}
+ className={`card-item${doc === this.curDoc() ? '-active' : this.isAnyChildContentActive() ? '-inactive' : ''}`}
onPointerUp={() => this.cardPointerUp(doc)}
style={{
width: this.childPanelWidth(),
height: 'max-content',
- transform: `translateY(${this.adjustCardYtoFitArch(doc === this._curDoc, index)}px)
+ transform: `translateY(${this.adjustCardYtoFitArch(doc === this.curDoc(), index)}px)
translateX(calc(${translateToCenterIfActive()}% + ${this.horizontalAdjustmentForPartialRows(index, cardsInRow)}px))
- rotate(${doc !== this._curDoc ? this.rotate(index) : 0}rad)
- scale(${doc === this._curDoc ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.1 : 1})`,
+ rotate(${doc !== this.curDoc()? this.rotate(index) : 0}rad)
+ scale(${doc === this.curDoc()? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.1 : 1})`,
}} // prettier-ignore
onPointerEnter={() => this.setHoveredNodeIndex(index)}
onPointerLeave={() => this.setHoveredNodeIndex(-1)}>
@@ -651,10 +661,10 @@ export class CollectionCardView extends CollectionSubView() {
isContentActive: emptyFunction,
ScreenToLocalTransform: this.contentScreenToLocalXf,
});
- answered = action(() => {
- this._curDoc = this.curDoc ? this.filteredChildDocs()[(this.filteredChildDocs().findIndex(d => d === this.curDoc()) + 1) % (this.filteredChildDocs().length || 1)] : undefined;
- });
- curDoc = () => this._curDoc;
+ answered = () => {
+ this.layoutDoc._card_curDoc = this.curDoc() ? this.filteredChildDocs()[(this.filteredChildDocs().findIndex(d => d === this.curDoc()) + 1) % (this.filteredChildDocs().length || 1)] : undefined;
+ };
+ curDoc = () => DocCast(this.layoutDoc._card_curDoc);
render() {
const fitContentScale = this.childCards.length === 0 ? 1 : this.fitContentScale;
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index a71cc43ba..c080ba27e 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -1,6 +1,7 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
+import { computedFn } from 'mobx-utils';
import * as React from 'react';
import { returnZero } from '../../../ClientUtils';
import { Utils } from '../../../Utils';
@@ -8,14 +9,15 @@ import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { DocumentType } from '../../documents/DocumentTypes';
+import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
import { Transform } from '../../util/Transform';
+import { PinDocView } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { DocumentView } from '../nodes/DocumentView';
import { FocusViewOptions } from '../nodes/FocusViewOptions';
import './CollectionCarousel3DView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
-import { computedFn } from 'mobx-utils';
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = require('../global/globalCssVariables.module.scss');
@@ -30,6 +32,9 @@ export class CollectionCarousel3DView extends CollectionSubView() {
makeObservable(this);
}
+ componentDidMount(): void {
+ this._props.setContentViewBox?.(this);
+ }
componentWillUnmount() {
this._dropDisposer?.();
}
@@ -70,33 +75,45 @@ export class CollectionCarousel3DView extends CollectionSubView() {
? false
: undefined
);
- contentScreenToLocalXf = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1);
+ contentScreenToLocalXf = () => this._props.ScreenToLocalTransform().translate(0, (-(Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) / this.nativeScaling());
childScreenLeftToLocal = () =>
this.contentScreenToLocalXf()
- .translate(-(this.panelWidth() - this.panelWidth() * this.sideScale) / 2, -(this.panelHeight() - this.panelHeight() * this.sideScale) / 2 - (Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight())
+ .translate(
+ (-this.panelWidth() * (1 - this.sideScale)) / 2, //
+ (-this.panelHeight() * (1 - this.sideScale)) / 2
+ )
.scale(1 / this.sideScale);
childScreenRightToLocal = () =>
this.contentScreenToLocalXf()
- .translate(-2 * this.panelWidth() - (this.panelWidth() - this.panelWidth() * this.sideScale) / 2, -(this.panelHeight() - this.panelHeight() * this.sideScale) / 2 - (Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight())
+ .translate(
+ -2 * this.panelWidth() - (this.panelWidth() * (1 - this.sideScale)) / 2, //
+ (-this.panelHeight() * (1 - this.sideScale)) / 2
+ )
.scale(1 / this.sideScale);
childCenterScreenToLocal = () =>
this.contentScreenToLocalXf()
.translate(
-this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, // Focused Doc is shifted right by 1/3 panel width then left by increased size percent of center * 1/2 * panel width / 3
- -((Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2
- ) // top is top margin % of panelHeight - increased size percent of center * panelHeight / 2
+ ((this.centerScale - 1) * this.panelHeight()) / 2
+ )
.scale(1 / this.centerScale);
focus = (anchor: Doc, options: FocusViewOptions): Opt<number> => {
- const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]);
- if (anchor.type !== DocumentType.CONFIG && !docs.includes(anchor)) return undefined;
- options.didMove = true;
- const target = DocCast(anchor.annotationOn) ?? anchor;
- const index = docs.indexOf(target);
- index !== -1 && (this.layoutDoc._carousel_index = index);
+ const docs = DocListCast(this.Document[this.fieldKey]);
+ if (anchor.type === DocumentType.CONFIG || docs.includes(anchor)) {
+ const newIndex = anchor.config_carousel_index ?? docs.getIndex(DocCast(anchor.annotationOn, anchor));
+ options.didMove = newIndex !== this.layoutDoc._carousel_index;
+ options.didMove && (this.layoutDoc._carousel_index = newIndex);
+ }
return undefined;
};
-
+ getAnchor = (addAsAnnotation: boolean) => {
+ const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document, config_carousel_index: this.layoutDoc._carousel_index as number });
+ PinDocView(anchor, { pinData: { collectionType: true, filters: true } }, this.Document);
+ addAsAnnotation && Doc.AddDocToList(this.dataDoc, this.fieldKey + '_annotations', anchor); // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered
+ return anchor;
+ };
+ addDocTab = this.addLinkedDocTab;
@computed get content() {
const currentIndex = NumCast(this.layoutDoc._carousel_index);
const displayDoc = (child: Doc, dxf: () => Transform) => (
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 1f2bc908f..f714e2a00 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -3,12 +3,16 @@ import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { StopEvent, returnOne, returnZero } from '../../../ClientUtils';
-import { Doc, Opt } from '../../../fields/Doc';
+import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { DocumentType } from '../../documents/DocumentTypes';
+import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
+import { PinDocView } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { DocumentView } from '../nodes/DocumentView';
import { FieldViewProps } from '../nodes/FieldView';
+import { FocusViewOptions } from '../nodes/FocusViewOptions';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import './CollectionCarouselView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
@@ -27,6 +31,9 @@ export class CollectionCarouselView extends CollectionSubView() {
makeObservable(this);
}
+ componentDidMount(): void {
+ this._props.setContentViewBox?.(this);
+ }
componentWillUnmount() {
this._dropDisposer?.();
}
@@ -67,6 +74,24 @@ export class CollectionCarouselView extends CollectionSubView() {
curDoc = () => this.carouselItems[this.carouselIndex]?.layout;
+ focus = (anchor: Doc, options: FocusViewOptions): Opt<number> => {
+ const docs = DocListCast(this.Document[this.fieldKey]);
+ if (anchor.type === DocumentType.CONFIG || docs.includes(anchor)) {
+ const newIndex = anchor.config_carousel_index ?? docs.getIndex(DocCast(anchor.annotationOn, anchor));
+ options.didMove = newIndex !== this.layoutDoc._carousel_index;
+ options.didMove && (this.layoutDoc._carousel_index = newIndex);
+ }
+ return undefined;
+ };
+
+ getAnchor = (addAsAnnotation: boolean) => {
+ const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document, config_carousel_index: this.carouselIndex });
+ PinDocView(anchor, { pinData: { collectionType: true, filters: true } }, this.Document);
+ addAsAnnotation && Doc.AddDocToList(this.dataDoc, this.fieldKey + '_annotations', anchor); // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered
+ return anchor;
+ };
+ addDocTab = this.addLinkedDocTab;
+
captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<FieldViewProps>, property: string) => {
// first look for properties on the document in the carousel, then fallback to properties on the container
const childValue = doc?.['caption_' + property] ? this._props.styleProvider?.(doc, captionProps, property) : undefined;
@@ -113,6 +138,7 @@ export class CollectionCarouselView extends CollectionSubView() {
LayoutTemplateString={this._props.childLayoutString}
TemplateDataDocument={DocCast(Doc.Layout(doc).resolvedDataDoc)}
childFilters={this.childDocFilters}
+ focus={this.focus}
hideDecorations={BoolCast(this.layoutDoc.layout_hideDecorations)}
addDocument={this._props.addDocument}
ScreenToLocalTransform={this.contentScreenToLocalXf}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index e1786d2c9..3e8138390 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -453,7 +453,7 @@ export class CollectionDockingView extends CollectionSubView() {
}
}
}
- if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && Doc.ActiveTool !== InkTool.Ink) {
e.stopPropagation();
}
};
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 486c826b6..c3047e5fb 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
/* eslint-disable no-use-before-define */
import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
@@ -59,7 +58,6 @@ export enum TrimScope {
@observer
export class CollectionStackedTimeline extends CollectionSubView<CollectionStackedTimelineProps>() {
- // eslint-disable-next-line no-use-before-define
public static SelectingRegions: Set<CollectionStackedTimeline> = new Set();
public static StopSelecting() {
this.SelectingRegions.forEach(
@@ -171,7 +169,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
makeDocUnfiltered = (doc: Doc) => this.childDocList?.some(item => item === doc);
- getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> =>
+ getView = (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> =>
new Promise<Opt<DocumentView>>(res => {
if (doc.hidden) options.didMove = !(doc.hidden = false);
const findDoc = (finish: (dv: DocumentView) => void) => DocumentView.addViewRenderedCb(doc, dv => finish(dv));
@@ -600,7 +598,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
pointerEvents: 'none',
}}>
<StackedTimelineAnchor
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
mark={d.anchor}
containerViewPath={this._props.containerViewPath}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 48aac3a68..0c059f729 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -9,7 +9,7 @@ import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
import { GestureUtils } from '../../../pen-gestures/GestureUtils';
@@ -27,6 +27,7 @@ import { ViewBoxBaseComponent } from '../DocComponent';
import { FieldViewProps } from '../nodes/FieldView';
import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
import { FlashcardPracticeUI } from './FlashcardPracticeUI';
+import { OpenWhere, OpenWhereMod } from '../nodes/OpenWhere';
export interface CollectionViewProps extends React.PropsWithChildren<FieldViewProps> {
isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc)
@@ -130,6 +131,17 @@ export function CollectionSubView<X>() {
@computed get childDocList() {
return Cast(this.dataField, listSpec(Doc));
}
+
+ addLinkedDocTab = (docsIn: Doc | Doc[], location: OpenWhere) => {
+ const doc = toList(docsIn).lastElement();
+ const where = location.split(':')[0];
+ if (where === OpenWhere.lightbox && (this.childDocList?.includes(doc) || this.childLayoutPairs.map(pair => pair.layout)?.includes(doc))) {
+ if (doc.hidden) doc.hidden = false;
+ if (!location.includes(OpenWhereMod.always)) return true;
+ }
+ return this._props.addDocTab(docsIn, location);
+ };
+
collectionFilters = () => this._focusFilters ?? StrListCast(this.Document._childFilters);
collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.Document._childFiltersByRanges, listSpec('string'), []);
// child filters apply to the descendants of the documents in this collection
@@ -519,6 +531,7 @@ export function CollectionSubView<X>() {
};
protected _sideBtnWidth = 35;
+ protected _sideBtnMaxPanelPct = 0.15;
@observable _filterFunc: ((doc: Doc) => boolean) | undefined = undefined;
/**
* How much the content of the collection is being scaled based on its nesting and its fit-to-width settings
@@ -529,7 +542,7 @@ export function CollectionSubView<X>() {
* This takes the desired screen space size and converts into collection coordinates. It then returns the smaller of the converted
* size or a fraction of the collection view.
*/
- @computed get maxWidgetSize() { return Math.min(this._sideBtnWidth * this.contentScaling, (this._props.fitWidth?.(this.Document) && this._props.PanelWidth() > NumCast(this.layoutDoc._width)? 1: 0.25) * NumCast(this.layoutDoc.width, 1)); } // prettier-ignore
+ @computed get maxWidgetSize() { return Math.min(this._sideBtnWidth * this.contentScaling, (this._props.fitWidth?.(this.Document) && this._props.PanelWidth() > NumCast(this.layoutDoc._width)? 1: this._sideBtnMaxPanelPct) * NumCast(this.layoutDoc.width, 1)); } // prettier-ignore
/**
* This computes a scale factor for UI elements so that they shrink and grow as the collection does in screen space.
* Note, the scale factor does not allow for elements to grow larger than their native screen space size.
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 8a24db330..d75c633ac 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -52,7 +52,7 @@ export class CollectionTimeView extends CollectionSubView() {
title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as unknown as string, // title can take a functiono or a string
annotationOn: this.Document,
});
- PinDocView(anchor, { pinData: { type_collection: true, pivot: true, filters: true } }, this.Document);
+ PinDocView(anchor, { pinData: { collectionType: true, pivot: true, filters: true } }, this.Document);
if (addAsAnnotation) {
// when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered
@@ -147,7 +147,6 @@ export class CollectionTimeView extends CollectionSubView() {
return (
<div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this._props.isContentActive() ? undefined : 'none' }} onClick={this.contentsDown}>
<CollectionFreeFormView
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
engineProps={{ pivotField: this.pivotField, childFilters: this.childDocFilters, childFiltersByRanges: this.childDocRangeFilters }}
fitContentsToBox={returnTrue}
@@ -257,7 +256,6 @@ ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBou
const pivotView = DocumentView.getDocumentView(pivotDoc);
if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) {
if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) {
- // eslint-disable-next-line prefer-destructuring
pivotDoc._pivotField = filterVals[0];
}
}
diff --git a/src/client/views/collections/FlashcardPracticeUI.tsx b/src/client/views/collections/FlashcardPracticeUI.tsx
index 9e9318c0a..c298bff22 100644
--- a/src/client/views/collections/FlashcardPracticeUI.tsx
+++ b/src/client/views/collections/FlashcardPracticeUI.tsx
@@ -58,7 +58,7 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
get practiceField() { return this._props.fieldKey + "_practice"; } // prettier-ignore
@computed get filterDoc() { return DocListCast(Doc.MyContextMenuBtns.data).find(doc => doc.title === 'Filter'); } // prettier-ignore
- @computed get practiceMode() { return this._props.allChildDocs().some(doc => doc._layout_isFlashcard) ? StrCast(this._props.layoutDoc.practiceMode) : ''; } // prettier-ignore
+ @computed get practiceMode() { return this._props.allChildDocs().some(doc => doc._flashcardType) ? StrCast(this._props.layoutDoc.practiceMode) : ''; } // prettier-ignore
btnHeight = () => NumCast(this.filterDoc?.height) * Math.min(1, this._props.ScreenToLocalBoxXf().Scale);
btnWidth = () => (!this.filterDoc ? 1 : (this.btnHeight() * NumCast(this.filterDoc._width)) / NumCast(this.filterDoc._height));
@@ -127,7 +127,7 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
const setColor = (mode: practiceMode) => (StrCast(this.practiceMode) === mode ? 'white' : 'lightgray');
const togglePracticeMode = (mode: practiceMode) => this.setPracticeMode(mode === this.practiceMode ? undefined : mode);
- return !this._props.allChildDocs().some(doc => doc._layout_isFlashcard) ? null : (
+ return !this._props.allChildDocs().some(doc => doc._layout_flashcardType) ? null : (
<div
className="FlashcardPracticeUI-practiceModes"
style={{
@@ -179,7 +179,7 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
</div>
);
}
- tryFilterOut = (doc: Doc) => (this.practiceMode && BoolCast(doc?._layout_isFlashcard) && doc[this.practiceField] === practiceVal.CORRECT ? true : false); // show only cards that aren't marked as correct
+ tryFilterOut = (doc: Doc) => (this.practiceMode && BoolCast(doc?._flashcardType) && doc[this.practiceField] === practiceVal.CORRECT ? true : false); // show only cards that aren't marked as correct
render() {
return (
<div className="FlashcardPracticeUI">
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 5bfdee1f5..60728877a 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -285,6 +285,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
static Activate = (tabDoc: Doc) => {
const tab = Array.from(CollectionDockingView.Instance?.tabMap ?? []).find(findTab => findTab.DashDoc === tabDoc && !findTab.contentItem.config.props.keyValue);
+ if (tab && tab.header.parent._activeContentItem === tab.contentItem) return false;
tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
return tab !== undefined;
};
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts b/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts
index 6ad67a864..8530f7a23 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormClusters.ts
@@ -1,4 +1,4 @@
-import { action, observable } from 'mobx';
+import { action, observable, untracked } from 'mobx';
import { CollectionFreeFormView } from '.';
import { intersectRect } from '../../../../Utils';
import { Doc, Opt } from '../../../../fields/Doc';
@@ -179,7 +179,9 @@ export class CollectionFreeFormClusters {
};
styleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => {
- if (doc && this.childDocs?.includes(doc))
+ // without untracked, every inquired style property for any Doc will be invalidated if a change is made to the collection's childDocs.
+ // this prevents that by assuming that a Doc is generally always (or never) a member of childDocs - if it's removed or added, then all of its properties get updated anyway.
+ if (doc && untracked(() => this.childDocs)?.includes(doc))
switch (property.split(':')[0]) {
case StyleProp.BackgroundColor:
{
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx
index 5d8373fc7..8b9a3e0ec 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx
@@ -29,7 +29,7 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio
}
_firstDocPos = { x: 0, y: 0 };
- constructor(props: any) {
+ constructor(props: CollectionFreeFormInfoUIProps) {
super(props);
makeObservable(this);
this._currState = this.setupStates();
@@ -163,7 +163,7 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio
return presentDocs;
}],
// eslint-disable-next-line no-use-before-define
- activePen: [() => activeTool() === InkTool.Pen, () => penMode],
+ activePen: [() => activeTool() === InkTool.Ink, () => penMode],
},
'documentation.png',
() => TopBar.Instance.FlipDocumentationIcon()
@@ -187,7 +187,7 @@ export class CollectionFreeFormInfoUI extends ObservableReactComponent<Collectio
const penMode = InfoState('You\'re in pen mode. Click and drag to draw your first masterpiece.', {
// activePen: [() => activeTool() === InkTool.Eraser, () => eraserMode],
- activePen: [() => activeTool() !== InkTool.Pen, () => viewedLink],
+ activePen: [() => activeTool() !== InkTool.Ink, () => viewedLink],
}); // prettier-ignore
// const eraserMode = InfoState('You\'re in eraser mode. Say goodbye to your first masterpiece.', {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d2bc8f2c2..f2a5780c5 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -10,7 +10,7 @@ import { DateField } from '../../../../fields/DateField';
import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc';
import { DocData, Height, Width } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
-import { InkData, InkField, InkTool, Segment } from '../../../../fields/InkField';
+import { InkData, InkEraserTool, InkField, InkInkTool, InkTool, Segment } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
import { RichTextField } from '../../../../fields/RichTextField';
import { listSpec } from '../../../../fields/Schema';
@@ -36,11 +36,24 @@ import { ContextMenu } from '../../ContextMenu';
import { InkingStroke } from '../../InkingStroke';
import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView';
import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp';
-import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveEraserWidth, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, DocumentView, SetActiveInkColor, SetActiveInkWidth } from '../../nodes/DocumentView';
+import {
+ ActiveInkArrowEnd,
+ ActiveInkArrowStart,
+ ActiveInkDash,
+ ActiveEraserWidth,
+ ActiveInkFillColor,
+ ActiveInkBezierApprox,
+ ActiveInkColor,
+ ActiveInkWidth,
+ ActiveIsInkMask,
+ DocumentView,
+ SetActiveInkColor,
+ SetActiveInkWidth,
+} from '../../nodes/DocumentView';
import { FieldViewProps } from '../../nodes/FieldView';
import { FocusViewOptions } from '../../nodes/FocusViewOptions';
import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox';
-import { OpenWhere, OpenWhereMod } from '../../nodes/OpenWhere';
+import { OpenWhere } from '../../nodes/OpenWhere';
import { PinDocView, PinProps } from '../../PinFuncs';
import { AnnotationPalette } from '../../smartdraw/AnnotationPalette';
import { DrawingOptions, SmartDrawHandler } from '../../smartdraw/SmartDrawHandler';
@@ -389,7 +402,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return undefined;
};
- getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> =>
+ getView = (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> =>
new Promise<Opt<DocumentView>>(res => {
if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false);
if (doc === this.Document) {
@@ -497,13 +510,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
// prettier-ignore
const hit = this._clusters.handlePointerDown(this.screenToFreeformContentsXf.transformPoint(e.clientX, e.clientY));
switch (Doc.ActiveTool) {
- case InkTool.Highlighter:
- case InkTool.Write:
- case InkTool.Pen:
+ case InkTool.Ink:
break; // the GestureOverlay handles ink stroke input -- either as gestures, or drying as ink strokes that are added to document views
- case InkTool.StrokeEraser:
- case InkTool.SegmentEraser:
- case InkTool.RadiusEraser:
+ case InkTool.Eraser:
this._batch = UndoManager.StartBatch('collectionErase');
this._eraserPts.length = 0;
setupMoveUpEvents(this, e, this.onEraserMove, this.onEraserUp, this.onEraserClick, hit !== -1);
@@ -543,7 +552,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const { points } = ge;
const B = this.screenToFreeformContentsXf.transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
const inkDoc = this.createInkDoc(points, B);
- if (Doc.ActiveTool === InkTool.Write) {
+ if (Doc.ActiveInk === InkInkTool.Highlight) inkDoc[DocData].backgroundColor = 'transparent';
+ if (Doc.ActiveInk === InkInkTool.Write) {
this.unprocessedDocs.push(inkDoc);
CollectionFreeFormView.collectionsWithUnprocessedInk.add(this);
}
@@ -606,7 +616,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const currPoint = { X: e.clientX, Y: e.clientY };
this._eraserPts.push([currPoint.X, currPoint.Y]);
this._eraserPts = this._eraserPts.slice(Math.max(0, this._eraserPts.length - 5));
- if (Doc.ActiveTool === InkTool.RadiusEraser) {
+ if (Doc.ActiveEraser === InkEraserTool.Radius) {
const strokeMap: Map<DocumentView, number[]> = this.getRadiusEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint);
strokeMap.forEach((intersects, stroke) => {
if (!this._deleteList.includes(stroke)) {
@@ -614,13 +624,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
SetActiveInkWidth(StrCast(stroke.Document.stroke_width?.toString()) || '1');
SetActiveInkColor(StrCast(stroke.Document.color?.toString()) || 'black');
const segments = this.radiusErase(stroke, intersects.sort());
- segments?.forEach(segment =>
- this.forceStrokeGesture(
- e,
- Gestures.Stroke,
- segment.reduce((data, curve) => [...data, ...curve.points.map(p => stroke.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[])
- )
- );
+ segments?.forEach(segment => {
+ const points = segment.reduce((data, curve) => [...data, ...curve.points.map(p => stroke.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]);
+ const bounds = InkField.getBounds(points);
+ const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height);
+ const inkDoc = this.createInkDoc(points, B);
+ ['color', 'fillColor', 'stroke_width', 'stroke_dash', 'stroke_bezier'].forEach(field => {
+ inkDoc[DocData][field] = stroke.dataDoc[field];
+ });
+ this.addDocument(inkDoc);
+ });
}
stroke.layoutDoc.opacity = 0;
stroke.layoutDoc.dontIntersect = true;
@@ -632,7 +645,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
SetActiveInkWidth(StrCast(intersect.inkView.Document.stroke_width?.toString()) || '1');
SetActiveInkColor(StrCast(intersect.inkView.Document.color?.toString()) || 'black');
// create a new curve by appending all curves of the current segment together in order to render a single new stroke.
- if (Doc.ActiveTool !== InkTool.StrokeEraser) {
+ if (Doc.ActiveEraser !== InkEraserTool.Stroke) {
// this._eraserLock++;
const segments = this.segmentErase(intersect.inkView, intersect.t); // intersect.t is where the eraser intersected the ink stroke - want to remove the segment that starts at the intersection just before this t value and goes to the one just after it
const newStrokes = segments?.map(segment => {
@@ -1195,14 +1208,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
y: B.y - inkWidth / 2,
_width: B.width + inkWidth,
_height: B.height + inkWidth,
- stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
+ stroke_showLabel: !BoolCast(Doc.UserDoc().activeHideTextLabels)}, // prettier-ignore
inkWidth,
ActiveInkColor(),
ActiveInkBezierApprox(),
- ActiveFillColor(),
- ActiveArrowStart(),
- ActiveArrowEnd(),
- ActiveDash(),
+ ActiveInkFillColor(),
+ ActiveInkArrowStart(),
+ ActiveInkArrowEnd(),
+ ActiveInkDash(),
ActiveIsInkMask()
);
};
@@ -1235,14 +1248,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
y: B.y - inkWidth / 2,
_width: B.width + inkWidth,
_height: B.height + inkWidth,
- stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
+ stroke_showLabel: BoolCast(Doc.UserDoc().activeHideTextLabels)}, // prettier-ignore
inkWidth,
opts.autoColor ? stroke[1] : ActiveInkColor(),
ActiveInkBezierApprox(),
- stroke[2] === 'none' ? ActiveFillColor() : stroke[2],
- ActiveArrowStart(),
- ActiveArrowEnd(),
- ActiveDash(),
+ stroke[2] === 'none' ? ActiveInkFillColor() : stroke[2],
+ ActiveInkArrowStart(),
+ ActiveInkArrowEnd(),
+ ActiveInkDash(),
ActiveIsInkMask()
);
this._drawing.push(inkDoc);
@@ -1596,21 +1609,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
case undefined:
case OpenWhere.lightbox:
- {
- const firstDoc = docs[0];
- if (this.layoutDoc._isLightbox) {
- this._lightboxDoc = firstDoc;
- return true;
- }
- if (firstDoc === this.Document || this.childDocList?.includes(firstDoc) || this.childLayoutPairs.map(pair => pair.layout)?.includes(firstDoc)) {
- if (firstDoc.hidden) firstDoc.hidden = false;
- if (!location.includes(OpenWhereMod.always)) return true;
- }
+ if (this.layoutDoc._isLightbox) {
+ this._lightboxDoc = docs[0];
+ return true;
}
- break;
+ return this.addLinkedDocTab(docsIn, location);
default:
}
- return this._props.addDocTab(docs, location);
+ return this._props.addDocTab(docsIn, location);
});
getCalculatedPositions(pair: { layout: Doc; data?: Doc }): PoolData {
const random = (min: number, max: number, x: number, y: number) => /* min should not be equal to max */ min + (((Math.abs(x * y) * 9301 + 49297) % 233280) / 233280) * (max - min);
@@ -1750,7 +1756,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
});
PinDocView(
anchor,
- { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ? { ...pinProps.pinData, poslayoutview: pinProps.pinData.dataview } : {}), pannable: !this.Document.isGroup, type_collection: true, filters: true } },
+ { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ? { ...pinProps.pinData, poslayoutview: pinProps.pinData.dataview } : {}), pannable: !this.Document.isGroup, collectionType: true, filters: true } },
this.Document
);
@@ -2202,7 +2208,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
width: `${100 / this.nativeDimScaling}%`,
height: this._props.getScrollHeight?.() ?? `${100 / this.nativeDimScaling}%`,
}}>
- {Doc.ActiveTool === InkTool.RadiusEraser && this._showEraserCircle && (
+ {Doc.ActiveTool === InkTool.Eraser && Doc.ActiveEraser === InkEraserTool.Radius && this._showEraserCircle && (
<div
onPointerMove={this.onCursorMove}
style={{
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index c865c681d..ddc50871d 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -690,7 +690,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
}}
style={{
overflow: StrCast(this._props.Document._overflow),
- cursor: [InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool) || this._visible ? 'crosshair' : 'pointer',
+ cursor: Doc.ActiveTool === InkTool.Ink || this._visible ? 'crosshair' : 'pointer',
}}
onDragOver={e => e.preventDefault()}
onScroll={e => {
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 6ffb0865a..7f519b065 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -188,7 +188,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<SchemaRowBoxProps>() {
selectedCells={this.selectedCells}
selectedCol={this.selectedCol}
setColumnValues={this.setColumnValues}
- oneLine={BoolCast(this.schemaDoc?._singleLine)}
+ oneLine={BoolCast(this.schemaDoc?._schema_singleLine)}
menuTarget={this.schemaView.MenuTarget}
transform={() => {
const ind = index === this.schemaView.columnKeys.length - 1 ? this.schemaView.columnKeys.length - 3 : index;
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 954c79f7d..40144c4ce 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -3,7 +3,7 @@ import { Colors } from 'browndash-components';
import { runInAction } from 'mobx';
import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
-import { InkTool } from '../../../fields/InkField';
+import { InkEraserTool, InkInkTool, InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
import { WebField } from '../../../fields/URLField';
@@ -16,21 +16,20 @@ import { SnappingManager } from '../../util/SnappingManager';
import { UndoManager, undoable } from '../../util/UndoManager';
import { GestureOverlay } from '../GestureOverlay';
import { InkTranscription } from '../InkTranscription';
-import { InkingStroke } from '../InkingStroke';
import { PropertiesView } from '../PropertiesView';
import { CollectionFreeFormView } from '../collections/collectionFreeForm';
import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
import {
ActiveEraserWidth,
- ActiveFillColor,
+ ActiveInkFillColor,
ActiveInkColor,
- ActiveInkHideTextLabels,
+ ActiveHideTextLabels,
ActiveInkWidth,
ActiveIsInkMask,
DocumentView,
- SetActiveFillColor,
+ SetActiveInkFillColor,
SetActiveInkColor,
- SetActiveInkHideTextLabels,
+ SetactiveHideTextLabels,
SetActiveInkWidth,
SetActiveIsInkMask,
SetEraserWidth,
@@ -60,20 +59,21 @@ ScriptingGlobals.add(function setView(view: string, getSelected: boolean) {
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: boolean) {
const selectedViews = DocumentView.Selected();
+ const selectedDoc = selectedViews.lastElement()?.Document;
+ const defaultFill = selectedDoc?._layout_isSvg ? () => StrCast(selectedDoc[DocData].fillColor) : !Doc.ActiveTool || Doc.ActiveTool === InkTool.None ? () => StrCast(Doc.UserDoc().textBackgroundColor, 'transparent') : () => ActiveInkFillColor();
+ const setDefaultFill = !Doc.ActiveTool || Doc.ActiveTool === InkTool.None ? (c: string) => { Doc.UserDoc().textBackgroundColor = c; }: SetActiveInkFillColor; // prettier-ignore
if (Doc.ActiveTool !== InkTool.None && !selectedViews.lastElement()?.Document._layout_isSvg) {
- if (checkResult) {
- return ActiveFillColor();
- }
- SetActiveFillColor(color ?? 'transparent');
+ if (checkResult) return defaultFill();
+ setDefaultFill(color ?? 'transparent');
} else if (selectedViews.length) {
if (checkResult) {
const selView = selectedViews.lastElement();
const fieldKey = selView.Document._layout_isSvg ? 'fillColor' : 'backgroundColor';
const layoutFrameNumber = Cast(selView.containerViewPath?.().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
const contentFrameNumber = Cast(selView.Document?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
- return CollectionFreeFormDocumentView.getStringValues(selView?.Document, contentFrameNumber)[fieldKey] ?? 'transparent';
+ return CollectionFreeFormDocumentView.getStringValues(selView?.Document, contentFrameNumber)[fieldKey] || defaultFill();
}
- selectedViews.some(dv => dv.ComponentView instanceof InkingStroke) && SetActiveFillColor(color ?? 'transparent');
+ setDefaultFill(color ?? 'transparent');
selectedViews.forEach(dv => {
const fieldKey = dv.Document._layout_isSvg ? 'fillColor' : 'backgroundColor';
const layoutFrameNumber = Cast(dv.containerViewPath?.().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
@@ -92,10 +92,13 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
} else {
const selected = DocumentView.SelectedDocs().length ? DocumentView.SelectedDocs() : LinkManager.Instance.currentLink ? [LinkManager.Instance.currentLink] : [];
if (checkResult) {
- return selected.lastElement()?._backgroundColor ?? 'transparent';
+ return selected.lastElement()?._backgroundColor ?? defaultFill();
}
- SetActiveFillColor(color ?? 'transparent');
- selected.forEach(doc => { doc[DocData].backgroundColor = color; }); // prettier-ignore
+ if (!selected.length) setDefaultFill(color ?? 'transparent');
+ else
+ selected.forEach(doc => {
+ doc[DocData][doc._layout_isSvg ? 'fillColor' : 'backgroundColor'] = color;
+ });
}
return '';
});
@@ -295,10 +298,10 @@ ScriptingGlobals.add(function setTagFilter(tag: string, added: boolean, checkRes
}, '');
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highlight' | 'fontSize' | 'alignment', value: string | number, checkResult?: boolean) {
+ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highlight' | 'fontSize', value: string | number, checkResult?: boolean) {
const editorView = RichTextMenu.Instance?.TextView?.EditorView;
// prettier-ignore
- const map: Map<'font'|'fontColor'|'highlight'|'fontSize'|'alignment', { checkResult: () => string | undefined; setDoc: () => void;}> = new Map([
+ const map: Map<'font'|'fontColor'|'highlight'|'fontSize', { checkResult: () => string | undefined; setDoc: () => void;}> = new Map([
['font', {
checkResult: () => RichTextMenu.Instance?.fontFamily,
setDoc: () => value && RichTextMenu.Instance?.setFontField(value.toString(), 'fontFamily'),
@@ -311,10 +314,6 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh
checkResult: () => RichTextMenu.Instance?.fontColor,
setDoc: () => value && RichTextMenu.Instance?.setFontField(value.toString(), 'fontColor'),
}],
- ['alignment', {
- checkResult: () => RichTextMenu.Instance?.textAlign,
- setDoc: () => { value && editorView?.state ? RichTextMenu.Instance?.align(editorView, editorView.dispatch, value.toString() as "center"|"left"|"right"):(Doc.UserDoc().textAlign = value); },
- }],
['fontSize', {
checkResult: () => RichTextMenu.Instance?.fontSize.replace('px', ''),
setDoc: () => {
@@ -334,7 +333,7 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh
return undefined;
});
-type attrname = 'noAutoLink' | 'dictation' | 'bold' | 'italics' | 'elide' | 'underline' | 'left' | 'center' | 'right' | 'vcent' | 'bullet' | 'decimal';
+type attrname = 'noAutoLink' | 'dictation' | 'fitBox' | 'bold' | 'italic' | 'elide' | 'underline' | 'left' | 'center' | 'right' | 'vcent' | 'bullet' | 'decimal';
type attrfuncs = [attrname, { checkResult: () => boolean; toggle?: () => unknown }];
// eslint-disable-next-line prefer-arrow-callback
@@ -343,14 +342,10 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?:
const editorView = textView?.EditorView;
// prettier-ignore
const alignments:attrfuncs[] = (['left','right','center','vcent'] as ("left"|"center"|"right"|"vcent")[]).map((where) =>
- [ where, { checkResult: () => editorView ? (where === 'vcent' ? RichTextMenu.Instance?.textVcenter ?? false:
- (RichTextMenu.Instance?.textAlign === where)):
- where === 'vcent' ? BoolCast(Doc.UserDoc()._layout_centered):
- (Doc.UserDoc().textAlign === where),
- toggle: () => { editorView?.state ? (where === 'vcent' ? RichTextMenu.Instance?.vcenterToggle():
- RichTextMenu.Instance?.align(editorView, editorView.dispatch, where)):
- where === 'vcent' ? Doc.UserDoc()._layout_centered = !Doc.UserDoc()._layout_centered:
- (Doc.UserDoc().textAlign = where); }
+ [ where, { checkResult: () => (where === 'vcent' ? RichTextMenu.Instance?.textVcenter ?? false:
+ (RichTextMenu.Instance?.textAlign === where)),
+ toggle: () => { (where === 'vcent' ? RichTextMenu.Instance?.vcenterToggle():
+ RichTextMenu.Instance?.align(editorView, editorView?.dispatch, where)); }
}]); // prettier-ignore
// prettier-ignore
const listings:attrfuncs[] = (['bullet','decimal'] as attrname[]).map(list =>
@@ -360,16 +355,18 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?:
const attrs:attrfuncs[] = [
['dictation', { checkResult: () => !!textView?._recordingDictation,
toggle: () => textView && runInAction(() => { textView._recordingDictation = !textView._recordingDictation;} ) }],
+ ['fitBox', { checkResult: () => RichTextMenu.Instance?.fitBox ?? false,
+ toggle: () => RichTextMenu.Instance?.toggleFitBox()}],
['elide', { checkResult: () => false,
toggle: () => editorView ? RichTextMenu.Instance?.elideSelection(): 0}],
['noAutoLink',{ checkResult: () => ((editorView && RichTextMenu.Instance?.noAutoLink) ?? false),
toggle: () => editorView && RichTextMenu.Instance?.toggleNoAutoLinkAnchor()}],
['bold', { checkResult: () => (editorView ? RichTextMenu.Instance?.bold??false : (Doc.UserDoc().fontWeight === 'bold')),
toggle: editorView ? RichTextMenu.Instance?.toggleBold : () => { Doc.UserDoc().fontWeight = Doc.UserDoc().fontWeight === 'bold' ? undefined : 'bold'; }}],
- ['italics', { checkResult: () => (editorView ? RichTextMenu.Instance?.italics ?? false : (Doc.UserDoc().fontStyle === 'italics')),
- toggle: editorView ? RichTextMenu.Instance?.toggleItalics : () => { Doc.UserDoc().fontStyle = Doc.UserDoc().fontStyle === 'italics' ? undefined : 'italics'; }}],
- ['underline', { checkResult: () => (editorView ? RichTextMenu.Instance?.underline ?? false: (Doc.UserDoc().textDecoration === 'underline')),
- toggle: editorView ? RichTextMenu.Instance?.toggleUnderline : () => { Doc.UserDoc().textDecoration = Doc.UserDoc().textDecoration === 'underline' ? undefined : 'underline'; } }]]
+ ['italic', { checkResult: () => (editorView ? RichTextMenu.Instance?.italic ?? false : (Doc.UserDoc().fontStyle === 'italic')),
+ toggle: editorView ? RichTextMenu.Instance?.toggleItalic : () => { Doc.UserDoc().fontStyle = Doc.UserDoc().fontStyle === 'italic' ? undefined : 'italic'; }}],
+ ['underline', { checkResult: () => (editorView ? RichTextMenu.Instance?.underline ?? false: (Doc.UserDoc().fontDecoration === 'underline')),
+ toggle: editorView ? RichTextMenu.Instance?.toggleUnderline : () => { Doc.UserDoc().fontDecoration = Doc.UserDoc().fontDecoration === 'underline' ? undefined : 'underline'; } }]]
const map = new Map(attrs.concat(alignments).concat(listings));
if (checkResult) {
@@ -379,43 +376,46 @@ ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?:
return undefined;
});
-function setActiveTool(toolIn: InkTool | Gestures, keepPrim: boolean, checkResult?: boolean) {
+function setActiveTool(tool: InkTool | InkEraserTool | InkInkTool | Gestures, keepPrim: boolean, checkResult?: boolean) {
InkTranscription.Instance?.createInkGroup();
- const tool = toolIn === InkTool.Eraser ? Doc.UserDoc().activeEraserTool : toolIn;
if (checkResult) {
- return ((Doc.ActiveTool === tool || (Doc.UserDoc().activeEraserTool === tool && (tool === toolIn || Doc.ActiveTool === tool))) && !GestureOverlay.Instance?.InkShape) || GestureOverlay.Instance?.InkShape === tool
- ? GestureOverlay.Instance?.KeepPrimitiveMode || ![Gestures.Circle, Gestures.Line, Gestures.Rectangle].includes(tool as Gestures)
+ return Doc.ActiveTool === tool || Doc.ActiveEraser === tool || Doc.ActiveInk === tool || SnappingManager.InkShape === tool
+ ? true //SnappingManager.KeepGestureMode || ![Gestures.Circle, Gestures.Line, Gestures.Rectangle].includes(tool as Gestures)
: false;
}
runInAction(() => {
+ const eraserTool = tool === InkTool.Eraser ? Doc.ActiveEraser : [InkEraserTool.Stroke, InkEraserTool.Radius, InkEraserTool.Segment].includes(tool as InkEraserTool) ? (tool as InkEraserTool) : undefined;
+ const inkTool = tool === InkTool.Ink ? Doc.ActiveInk : [InkInkTool.Pen, InkInkTool.Write, InkInkTool.Highlight].includes(tool as InkInkTool) ? (tool as InkInkTool) : undefined;
if (GestureOverlay.Instance) {
- GestureOverlay.Instance.KeepPrimitiveMode = keepPrim;
+ SnappingManager.SetKeepGestureMode(keepPrim);
}
if (Object.values(Gestures).includes(tool as Gestures)) {
- if (GestureOverlay.Instance.InkShape === tool && !keepPrim) {
+ if (SnappingManager.InkShape === tool && !keepPrim) {
Doc.ActiveTool = InkTool.None;
- GestureOverlay.Instance.InkShape = undefined;
+ SnappingManager.SetInkShape(undefined);
} else {
- Doc.ActiveTool = InkTool.Pen;
- GestureOverlay.Instance.InkShape = tool as Gestures;
+ Doc.ActiveTool = InkTool.Ink;
+ SnappingManager.SetInkShape(tool as Gestures);
}
- } else if (tool) {
- if (Doc.UserDoc().ActiveTool === tool) {
+ } else if (eraserTool) {
+ if (Doc.ActiveTool === InkTool.Eraser && Doc.ActiveTool === tool) {
Doc.ActiveTool = InkTool.None;
} else {
- if ([InkTool.StrokeEraser, InkTool.RadiusEraser, InkTool.SegmentEraser].includes(tool as InkTool)) {
- Doc.UserDoc().activeEraserTool = tool;
- }
- // pen or eraser
- if (Doc.ActiveTool === tool && !GestureOverlay.Instance.InkShape && !keepPrim) {
- Doc.ActiveTool = InkTool.None;
- } else {
- Doc.ActiveTool = tool as InkTool;
- GestureOverlay.Instance.InkShape = undefined;
- }
+ Doc.ActiveEraser = eraserTool;
+ Doc.ActiveTool = InkTool.Eraser;
+ SnappingManager.SetInkShape(undefined);
+ }
+ } else if (inkTool) {
+ if (Doc.ActiveTool === InkTool.Ink && Doc.ActiveTool === tool) {
+ Doc.ActiveTool = InkTool.None;
+ } else {
+ Doc.ActiveInk = inkTool;
+ Doc.ActiveTool = InkTool.Ink;
+ SnappingManager.SetInkShape(undefined);
}
} else {
- Doc.ActiveTool = InkTool.None;
+ if ((Doc.ActiveTool === tool || !tool) && !keepPrim) Doc.ActiveTool = InkTool.None;
+ else Doc.ActiveTool = tool as InkTool;
}
});
return undefined;
@@ -425,44 +425,44 @@ ScriptingGlobals.add(setActiveTool, 'sets the active ink tool mode');
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function activeEraserTool() {
- return StrCast(Doc.UserDoc().activeEraserTool, InkTool.StrokeEraser);
+ return StrCast(Doc.UserDoc().activeEraserTool, InkEraserTool.Stroke);
}, 'returns the current eraser tool');
// toggle: Set overlay status of selected document
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function setInkProperty(option: 'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor' | 'eraserWidth', value: string | number, checkResult?: boolean) {
- const selected = DocumentView.SelectedDocs().lastElement() ?? Doc.UserDoc();
+ const selected = DocumentView.SelectedDocs().lastElement();
// prettier-ignore
const map: Map<'inkMask' | 'labels' | 'fillColor' | 'strokeWidth' | 'strokeColor' | 'eraserWidth', { checkResult: () => number|boolean|string|undefined; setInk: (doc: Doc) => void; setMode: () => void }> = new Map([
['inkMask', {
checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected[DocData].stroke_isInkMask) : ActiveIsInkMask())),
setInk: (doc: Doc) => { doc[DocData].stroke_isInkMask = !doc.stroke_isInkMask; },
- setMode: () => selected?.type !== DocumentType.INK && SetActiveIsInkMask(!ActiveIsInkMask()),
+ setMode: () => SetActiveIsInkMask(value ? true : false)
}],
['labels', {
- checkResult: () => ((selected?._stroke_showLabel ? BoolCast(selected[DocData].stroke_showLabel) : ActiveInkHideTextLabels())),
- setInk: (doc: Doc) => { doc[DocData].stroke_showLabel = !doc.stroke_showLabel; },
- setMode: () => selected?.type !== DocumentType.INK && SetActiveInkHideTextLabels(!ActiveInkHideTextLabels()),
+ checkResult: () => ((selected?._layout_isSvg ? BoolCast(selected[DocData].stroke_showLabel) : !ActiveHideTextLabels())),
+ setInk: (doc: Doc) => { doc[DocData].stroke_showLabel = value; },
+ setMode: () => SetactiveHideTextLabels(value? false : true),
}],
['fillColor', {
- checkResult: () => (selected?._layout_isSvg ? StrCast(selected[DocData].fillColor) : ActiveFillColor() ?? "transparent"),
+ checkResult: () => (selected?._layout_isSvg ? StrCast(selected[DocData].fillColor) : ActiveInkFillColor() ?? "transparent"),
setInk: (doc: Doc) => { doc[DocData].fillColor = StrCast(value); },
- setMode: () => SetActiveFillColor(StrCast(value)),
+ setMode: () => SetActiveInkFillColor(StrCast(value)),
}],
[ 'strokeWidth', {
checkResult: () => (selected?._layout_isSvg ? NumCast(selected[DocData].stroke_width) : ActiveInkWidth()),
setInk: (doc: Doc) => { doc[DocData].stroke_width = NumCast(value); },
- setMode: () => { SetActiveInkWidth(value.toString()); selected?.type === DocumentType.INK && setActiveTool( GestureOverlay.Instance.InkShape ?? InkTool.Pen, true, false);},
+ setMode: () => SetActiveInkWidth(value.toString()),
}],
['strokeColor', {
checkResult: () => (selected?._layout_isSvg? StrCast(selected[DocData].color) : ActiveInkColor()),
setInk: (doc: Doc) => { doc[DocData].color = String(value); },
- setMode: () => { SetActiveInkColor(StrCast(value)); selected?.type === DocumentType.INK && setActiveTool(GestureOverlay.Instance.InkShape ?? InkTool.Pen, true, false);},
+ setMode: () => SetActiveInkColor(StrCast(value))
}],
[ 'eraserWidth', {
checkResult: () => ActiveEraserWidth() === 0 ? 1 : ActiveEraserWidth(),
setInk: (doc: Doc) => { },
- setMode: () => { SetEraserWidth(+value);},
+ setMode: () => SetEraserWidth(+value),
}]
]);
diff --git a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
index 3eb99f47a..8115bafbf 100644
--- a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
+++ b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable jsx-a11y/no-static-element-interactions */
-/* eslint-disable jsx-a11y/click-events-have-key-events */
import { action } from 'mobx';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
@@ -35,10 +33,10 @@ export function ButtonMenu() {
<div
className="newLightboxView-penBtn"
title="toggle pen annotation"
- style={{ background: Doc.ActiveTool === InkTool.Pen ? 'white' : undefined }}
+ style={{ background: Doc.ActiveTool === InkTool.Ink ? 'white' : undefined }}
onClick={e => {
e.stopPropagation();
- Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen;
+ Doc.ActiveTool = Doc.ActiveTool === InkTool.Ink ? InkTool.None : InkTool.Ink;
}}
/>
<div
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index d51b1cd3a..3905403ea 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,7 +1,8 @@
+import { Colors } from 'browndash-components';
import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { OmitKeys } from '../../../ClientUtils';
+import { DashColor, OmitKeys } from '../../../ClientUtils';
import { numberRange } from '../../../Utils';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { TransitionTimer } from '../../../fields/DocSymbols';
@@ -296,12 +297,12 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
transition: this.DataTransition(),
zIndex: this.ZIndex,
display: this.Width ? undefined : 'none',
+ mixBlendMode: !this.layoutDoc.disableMixBlend && DashColor(StrCast(this.layoutDoc[this.layoutDoc._layout_isSvg ? 'fillColor' : 'backgroundColor'], Colors.WHITE)).alpha() !== 1 ? 'multiply' : undefined,
}}>
{this.RenderCutoffProvider(this.Document) ? (
<div style={{ position: 'absolute', width: this.PanelWidth(), height: this.PanelHeight(), background: 'lightGreen' }} />
) : (
<DocumentView
- // eslint-disable-next-line react/jsx-props-no-spreading
{...OmitKeys(this._props,this.WrapperKeys.map(val => val.lower)).omit} // prettier-ignore
Document={this._props.Document}
renderDepth={this._props.renderDepth}
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index f6c33d6ba..672c189ba 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -63,8 +63,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
* @param useDoc doc to fill in instead of creating a Doc
* @returns the resulting flashcard Doc
*/
- public static createFlashcard(tuple: string, frontKey: string, backKey: string, useDoc?: Doc) {
- const [ktoken, atoken] = [ComparisonBox.ktoken, ComparisonBox.atoken];
+ public static createFlashcard(tuple3: string, frontKey: string, backKey: string, useDoc?: Doc) {
+ const [qtoken, ktoken, atoken] = [ComparisonBox.qtoken, ComparisonBox.ktoken, ComparisonBox.atoken];
+ const [title, tuple] = tuple3.split(qtoken);
const question = (tuple.includes(ktoken) ? tuple.split(ktoken)[0] : tuple).split(atoken)[0];
const rest = tuple.replace(question, '');
// prettier-ignore
@@ -82,7 +83,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
useDoc[DocData][backKey] = back;
return useDoc;
}
- return Docs.Create.FlashcardDocument('flashcard', front, back, { _width: 300, _height: 300 });
+ return Docs.Create.FlashcardDocument(title, front, back, { _width: 300, _height: 300 });
};
return keyword && keyword.toLowerCase() !== 'none' ? ComparisonBox.fetchImages(keyword).then(img => fillInFlashcard(img)) : fillInFlashcard();
}
@@ -95,12 +96,13 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
public static createFlashcardDeck(text: string, width: number, height: number, front: string, back: string) {
return Promise.all(
text
- .split(ComparisonBox.qtoken)
+ .toLowerCase()
+ .split(ComparisonBox.ttoken)
.filter(t => t)
.map(tuple => ComparisonBox.createFlashcard(tuple, front, back))
).then(docs => {
return Docs.Create.CarouselDocument(docs, {
- title: 'flashcard deck',
+ title: text,
_width: width,
_height: height,
_layout_fitWidth: false,
@@ -112,9 +114,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
}
private SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
- static qtoken = 'Question: ';
- static ktoken = 'Keyword: ';
- static atoken = 'Answer: ';
+ static qtoken = 'question: ';
+ static ktoken = 'keyword: ';
+ static atoken = 'answer: ';
+ static ttoken = 'title: ';
private _slideTiming = 200;
private _sideBtnWidth = 35;
private _closeRef = React.createRef<HTMLDivElement>();
@@ -183,7 +186,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
@computed get containerDoc() { return this._props.docViewPath().slice(-2)[0]?.Document; } // prettier-ignore
@computed get isQuizMode() { return this.containerDoc?.practiceMode === practiceMode.QUIZ; } // prettier-ignore
- @computed get isFlashcard() { return BoolCast(this.Document.layout_isFlashcard); } // prettier-ignore
+ @computed get isFlashcard() { return StrCast(this.Document.layout_flashcardType); } // prettier-ignore
@computed get frontKey() { return this._props.fieldKey + '_front'; } // prettier-ignore
@computed get backKey() { return this._props.fieldKey + '_back'; } // prettier-ignore
@computed get frontText() { return RTFCast(DocCast(this.dataDoc[this.frontKey]).text)?.Text; } // prettier-ignore
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 896048ab3..7925410e2 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -73,7 +73,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return <div className="dataVizBox-annotationLayer" style={{ height: this._props.PanelHeight(), width: this._props.PanelWidth() }} ref={this._annotationLayer} />;
}
marqueeDown = (e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive() && Doc.ActiveTool !== InkTool.Ink) {
setupMoveUpEvents(
this,
e,
@@ -323,7 +323,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
() => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar')
);
};
- getView = async (doc: Doc, options: FocusViewOptions) => {
+ getView = (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
options.didMove = true;
this.toggleSidebar();
@@ -453,7 +453,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action
onPointerDown = (e: React.PointerEvent): void => {
if ((this.Document._freeform_scale || 1) !== 1) return;
- if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this._props.isContentActive() && Doc.ActiveTool !== InkTool.Ink) {
this._props.select(false);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this._marqueeing = [e.clientX, e.clientY];
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 16c016d6c..7c601185e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -245,7 +245,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
}
updateIcons = (docs: Doc[]) => {
- console.log('called')
+ console.log('called');
docs.map(this.getIcon);
};
@@ -416,7 +416,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
const height = bottom - top;
const width = right - left;
const doc = !field.title.includes('$$')
- ? Docs.Create.TextDocument('', { _height: height, _width: width, title: field.title, x: left, y: top, _text_fontSize: `${height / 2}` })
+ ? Docs.Create.TextDocument('', { _height: height, _width: width, title: field.title, x: left, y: top, text_fontSize: `${height / 2}` })
: Docs.Create.ImageDocument('', { _height: height, _width: width, title: field.title.replace(/\$\$/g, ''), x: left, y: top });
return doc;
});
@@ -919,17 +919,17 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
@action setExpandedView = (info: { icon: ImageField; doc: Doc } | undefined) => {
if (info) {
const doc = info.doc;
- const wrapper: Doc = Docs.Create.FreeformDocument([info.doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''});
- const newInfo = {icon: new ImageField(''), doc: wrapper}
+ const wrapper: Doc = Docs.Create.FreeformDocument([info.doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: '' });
+ const newInfo = { icon: new ImageField(''), doc: wrapper };
this._expandedPreview = newInfo;
} else {
this._expandedPreview = info;
}
};
- get editingWindow(){
+ get editingWindow() {
const doc = this._expandedPreview?.doc ?? new Doc();
- const rendered =
+ const rendered = (
<div className="docCreatorMenu-expanded-template-preview">
<CollectionFreeFormView
Document={this._expandedPreview!.doc}
@@ -945,7 +945,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
removeDocument={returnFalse}
PanelWidth={() => this._menuDimensions.width - 10}
PanelHeight={() => this._menuDimensions.height - 60}
- ScreenToLocalTransform={() => new Transform(-this._pageX,-this._pageY, 1)}
+ ScreenToLocalTransform={() => new Transform(-this._pageX, -this._pageY, 1)}
renderDepth={5}
whenChildContentsActiveChanged={emptyFunction}
focus={emptyFunction}
@@ -961,14 +961,21 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
yPadding={0}
/>
</div>
-
+ );
return (
<div className="docCreatorMenu-expanded-template-preview">
- <div className="top-panel"/>
+ <div className="top-panel" />
{rendered}
<div className="right-buttons-panel">
- <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, () => {this._expandedPreview && this.updateIcons(this._suggestedTemplates.slice()); this.setExpandedView(undefined)})}>
+ <button
+ className="docCreatorMenu-menu-button section-reveal-options top-right"
+ onPointerDown={e =>
+ this.setUpButtonClick(e, () => {
+ this._expandedPreview && this.updateIcons(this._suggestedTemplates.slice());
+ this.setExpandedView(undefined);
+ })
+ }>
<FontAwesomeIcon icon="minimize" />
</button>
<button className="docCreatorMenu-menu-button section-reveal-options top-right-lower" onPointerDown={e => this.setUpButtonClick(e, () => this._expandedPreview && this._templateDocs.push(this._expandedPreview.doc))}>
@@ -976,7 +983,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> {
</button>
</div>
</div>
-
);
}
@@ -2260,11 +2266,11 @@ export class FieldUtils {
title: title,
x: coord.x,
y: coord.y,
- _text_fontSize: `${FieldUtils.calculateFontSize(width, height, content, true)}`,
+ text_fontSize: `${FieldUtils.calculateFontSize(width, height, content, true)}`,
backgroundColor: opts.backgroundColor ?? '',
text_fontColor: opts.color,
contentBold: opts.fontBold,
- textTransform: opts.fontTransform,
+ text_transform: opts.fontTransform,
color: opts.color,
_layout_borderRounding: `${opts.cornerRounding ?? 0}px`,
borderColor: opts.borderColor,
@@ -2306,7 +2312,7 @@ export class FieldUtils {
public static CarouselField = (coords: { tl: [number, number]; br: [number, number] }, parentWidth: number, parentHeight: number, title: string, fields: Doc[]) => {
const { width, height, coord } = FieldUtils.getDimensions(coords, parentWidth, parentHeight);
- const doc = Docs.Create.Carousel3DDocument(fields, { _height: height, _width: width, title: title, x: coord.x, y: coord.y, _text_fontSize: `${height / 2}` });
+ const doc = Docs.Create.Carousel3DDocument(fields, { _height: height, _width: width, title: title, x: coord.x, y: coord.y, text_fontSize: `${height / 2}` });
return doc;
};
@@ -2359,4 +2365,3 @@ export class FieldUtils {
// }]
// };
// }
-
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a343b9a39..30f9e6363 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -380,7 +380,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
};
onPointerMove = (e: PointerEvent): void => {
- if (e.buttons !== 1 || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) return;
+ if (e.buttons !== 1 || Doc.ActiveTool === InkTool.Ink) return;
if (!ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) {
this.cleanupPointerEvents();
@@ -880,7 +880,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
background: this.backgroundBoxColor,
opacity: this.opacity,
cursor: Doc.ActiveTool === InkTool.None ? 'grab' : 'crosshair',
- color: StrCast(this.layoutDoc.color, 'inherit'),
+ color: StrCast(this.Document._color, 'inherit'),
fontFamily: StrCast(this.Document._text_fontFamily, 'inherit'),
fontSize: Cast(this.Document._text_fontSize, 'string', null),
transform: this._animateScalingTo ? `scale(${this._animateScalingTo})` : undefined,
@@ -981,12 +981,10 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
type: SpringType.GENTLE,
...springMappings.gentle,
};
- switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) {
- case PresEffect.Expand: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Expand} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
- case PresEffect.Flip: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Flip} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
- case PresEffect.Rotate: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Rotate} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
- case PresEffect.Bounce: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Bounce} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
- case PresEffect.Roll: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Roll} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
+ const presEffect = StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect));
+ switch (presEffect) {
+ case PresEffect.Expand: case PresEffect.Flip: case PresEffect.Rotate: case PresEffect.Bounce:
+ case PresEffect.Roll: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={presEffect} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
// case PresEffect.Fade: return <SlideEffect doc={root} dir={dir} presEffect={PresEffect.Fade} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect>
case PresEffect.Fade: return <Fade {...effectProps}>{renderDoc}</Fade>
// keep as preset, doesn't really make sense with spring config
@@ -1562,55 +1560,45 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
} else func();
}
}
-
-export function ActiveFillColor(): string {
- const dv = DocumentView.Selected().lastElement() ?.Document._layout_isSvg ? DocumentView.Selected().lastElement() : undefined;
- return StrCast(dv?.Document.fillColor, StrCast(ActiveInkPen()?.activeFillColor, ""));
-} // prettier-ignore
-export function ActiveInkPen(): Doc { return Doc.UserDoc(); } // prettier-ignore
-export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, 'black'); } // prettier-ignore
-export function ActiveIsInkMask(): boolean { return BoolCast(ActiveInkPen()?.activeIsInkMask, false); } // prettier-ignore
-export function ActiveInkHideTextLabels(): boolean { return BoolCast(ActiveInkPen().activeInkHideTextLabels, false); } // prettier-ignore
-export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, ''); } // prettier-ignore
-export function ActiveArrowEnd(): string { return StrCast(ActiveInkPen()?.activeArrowEnd, ''); } // prettier-ignore
-export function ActiveArrowScale(): number { return NumCast(ActiveInkPen()?.activeArrowScale, 1); } // prettier-ignore
-export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash, '0'); } // prettier-ignore
-export function ActiveInkWidth(): number { return Number(ActiveInkPen()?.activeInkWidth); } // prettier-ignore
-export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); } // prettier-ignore
-export function ActiveEraserWidth(): number { return Number(ActiveInkPen()?.eraserWidth ?? 25); } // prettier-ignore
-
+export function ActiveHideTextLabels(): boolean { return BoolCast(Doc.UserDoc().activeHideTextLabels, false); } // prettier-ignore
+export function ActiveIsInkMask(): boolean { return BoolCast(Doc.UserDoc()?.activeIsInkMask, false); } // prettier-ignore
+export function ActiveEraserWidth(): number { return Number(Doc.UserDoc()?.activeEraserWidth ?? 25); } // prettier-ignore
+
+export function ActiveInkFillColor(): string { return StrCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}Fill`]); } // prettier-ignore
+export function ActiveInkColor(): string { return StrCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}Color`], 'black'); } // prettier-ignore
+export function ActiveInkArrowStart(): string { return StrCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}ArrowStart`], ''); } // prettier-ignore
+export function ActiveInkArrowEnd(): string { return StrCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}ArrowEnd`], ''); } // prettier-ignore
+export function ActiveInkArrowScale(): number { return NumCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}ArrowScale`], 1); } // prettier-ignore
+export function ActiveInkDash(): string { return StrCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}Dash`], '0'); } // prettier-ignore
+export function ActiveInkWidth(): number { return Number(Doc.UserDoc()?.[`active${Doc.ActiveInk}Width`]); } // prettier-ignore
+export function ActiveInkBezierApprox(): string { return StrCast(Doc.UserDoc()[`active${Doc.ActiveInk}Bezier`]); } // prettier-ignore
+
+export function SetActiveIsInkMask(value: boolean) { Doc.UserDoc() && (Doc.UserDoc().activeIsInkMask = value); } // prettier-ignore
+export function SetactiveHideTextLabels(value: boolean) { Doc.UserDoc() && (Doc.UserDoc().activeHideTextLabels = value); } // prettier-ignore
+export function SetEraserWidth(width: number): void { Doc.UserDoc() && (Doc.UserDoc().activeEraserWidth = width); } // prettier-ignore
export function SetActiveInkWidth(width: string): void {
- !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width);
+ !isNaN(parseInt(width)) && Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}Width`] = width);
}
-export function SetActiveBezierApprox(bezier: string): void {
- ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? '' : bezier);
+export function SetActiveInkBezierApprox(bezier: string): void {
+ Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}Bezier`] = isNaN(parseInt(bezier)) ? '' : bezier);
}
export function SetActiveInkColor(value: string) {
- ActiveInkPen() && (ActiveInkPen().activeInkColor = value);
-}
-export function SetActiveIsInkMask(value: boolean) {
- ActiveInkPen() && (ActiveInkPen().activeIsInkMask = value);
-}
-export function SetActiveInkHideTextLabels(value: boolean) {
- ActiveInkPen() && (ActiveInkPen().activeInkHideTextLabels = value);
-}
-export function SetActiveFillColor(value: string) {
- ActiveInkPen() && (ActiveInkPen().activeFillColor = value);
+ Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}Color`] = value);
}
-export function SetActiveArrowStart(value: string) {
- ActiveInkPen() && (ActiveInkPen().activeArrowStart = value);
+export function SetActiveInkFillColor(value: string) {
+ Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}Fill`] = value);
}
-export function SetActiveArrowEnd(value: string) {
- ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value);
+export function SetActiveInkArrowStart(value: string) {
+ Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}ArrowStart`] = value);
}
-export function SetActiveArrowScale(value: number) {
- ActiveInkPen() && (ActiveInkPen().activeArrowScale = value);
+export function SetActiveInkArrowEnd(value: string) {
+ Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}ArrowEnd`] = value);
}
-export function SetActiveDash(dash: string): void {
- !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash);
+export function SetActiveInkArrowScale(value: number) {
+ Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}ArrowScale`] = value);
}
-export function SetEraserWidth(width: number): void {
- ActiveInkPen() && (ActiveInkPen().eraserWidth = width);
+export function SetActiveInkDash(dash: string): void {
+ !isNaN(parseInt(dash)) && Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}`] = dash);
}
// eslint-disable-next-line prefer-arrow-callback
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index fefe25764..290c90d6e 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -122,7 +122,7 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
width: 'fit-content', // `${100 / scale}%`,
height: `${100 / scale}%`,
pointerEvents: !this._props.isSelected() ? 'none' : undefined,
- fontSize: StrCast(this.layoutDoc._text_fontSize),
+ fontSize: StrCast(this.Document._text_fontSize),
}}
onKeyDown={e => e.stopPropagation()}>
<EquationEditor ref={this._ref} value={StrCast(this.dataDoc.text, 'x')} spaceBehavesLikeTab onChange={this.onChange} autoCommands="pi theta sqrt sum prod alpha beta gamma rho" autoOperatorNames="sin cos tan" />
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.scss b/src/client/views/nodes/FontIconBox/FontIconBox.scss
index 2db285910..2405889cf 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.scss
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.scss
@@ -10,6 +10,13 @@
height: 3px !important;
}
}
+.fonticonbox {
+ margin: auto;
+ width: 100%;
+ .formLabel {
+ height: 5px;
+ }
+}
.menuButton {
height: 100%;
display: flex;
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index d4898eb3c..8c138c2ee 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -4,7 +4,7 @@ import { Button, ColorPicker, Dropdown, DropdownType, IconButton, IListItemProps
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { ClientUtils, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils';
+import { ClientUtils, DashColor, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils';
import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc';
import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { emptyFunction } from '../../../../Utils';
@@ -21,6 +21,8 @@ import { FieldView, FieldViewProps } from '../FieldView';
import { OpenWhere } from '../OpenWhere';
import './FontIconBox.scss';
import TrailsIcon from './TrailsIcon';
+import { InkTool } from '../../../../fields/InkField';
+import { ScriptField } from '../../../../fields/ScriptField';
export enum ButtonType {
TextButton = 'textBtn',
@@ -126,7 +128,8 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
background={SnappingManager.userBackgroundColor}
numberDropdownType={type}
showPlusMinus={false}
- tooltip={this.label}
+ formLabel={(StrCast(this.Document.title).startsWith(' ') ? '\u00A0' : '') + StrCast(this.Document.title)}
+ tooltip={StrCast(this.Document.toolTip, this.label)}
type={Type.PRIM}
min={NumCast(this.dataDoc.numBtnMin, 0)}
max={NumCast(this.dataDoc.numBtnMax, 100)}
@@ -149,64 +152,79 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
};
/**
+ * Displays custom dropdown menu for fonts -- this is a HACK -- fix for generality, don't copy
+ */
+ handleFontDropdown = (script: () => string, buttonList: string[]) => {
+ // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
+ return {
+ buttonList,
+ jsx: undefined,
+ selectedVal: script(),
+ getStyle: (val: string) => ({ fontFamily: val }),
+ };
+ };
+ /**
+ * Displays custom dropdown menu for view selection -- this is a HACK -- fix for generality, don't copy
+ */
+ handleViewDropdown = (script: ScriptField, buttonList: string[]) => {
+ const selected = Array.from(script?.script.run({ _readOnly_: true }).result as Doc[]);
+ const noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Card, CollectionViewType.Carousel3D, CollectionViewType.Carousel, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
+ return selected.length === 1 && selected[0].type === DocumentType.COL
+ ? {
+ buttonList: buttonList.filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value as CollectionViewType)),
+ getStyle: undefined,
+ selectedVal: StrCast(selected[0]._type_collection),
+ }
+ : {
+ jsx: selected.length ? (
+ <Popup
+ icon={<FontAwesomeIcon size="1x" icon={selected.length > 1 ? 'caret-down' : (Doc.toIcon(selected.lastElement()) as IconProp)} />}
+ text={selected.length === 1 ? ClientUtils.cleanDocumentType(StrCast(selected[0].type) as DocumentType) : selected.length + ' selected'}
+ type={Type.TERT}
+ color={SnappingManager.userColor}
+ background={SnappingManager.userVariantColor}
+ popup={<SelectedDocView selectedDocs={selected} />}
+ fillWidth
+ />
+ ) : (
+ <Button
+ text={`${Doc.ActiveTool === InkTool.None ? 'Text box' : Doc.ActiveInk} defaults`} //
+ type={Type.TERT}
+ color={SnappingManager.userColor}
+ background={SnappingManager.userVariantColor}
+ fillWidth
+ inactive
+ />
+ ),
+ };
+ };
+
+ /**
* Dropdown list
*/
@computed get dropdownListButton() {
const script = ScriptCast(this.Document.script);
-
- let noviceList: string[] = [];
- let text: string | undefined;
- let getStyle: (val: string) => { [key: string]: string } = () => ({});
- let icon: IconProp = 'caret-down';
- const isViewDropdown = script?.script.originalScript.startsWith('{ return setView');
- if (isViewDropdown) {
- const selected = Array.from(script?.script.run({ _readOnly_: true }).result as Doc[]);
- // const selected = DocumentView.SelectedDocs();
- if (selected.lastElement()) {
- if (StrCast(selected.lastElement().type) === DocumentType.COL) {
- text = StrCast(selected.lastElement()._type_collection);
- } else {
- if (selected.length > 1) {
- text = selected.length + ' selected';
- } else {
- text = ClientUtils.cleanDocumentType(StrCast(selected.lastElement().type) as DocumentType, '' as CollectionViewType);
- icon = Doc.toIcon(selected.lastElement());
- }
- return (
- <Popup
- icon={<FontAwesomeIcon size="1x" icon={icon} />}
- text={text}
- type={Type.TERT}
- color={SnappingManager.userColor}
- background={SnappingManager.userVariantColor}
- popup={<SelectedDocView selectedDocs={selected} />}
- fillWidth
- />
- );
- }
- } else {
- return <Button text="None Selected" type={Type.TERT} color={SnappingManager.userColor} background={SnappingManager.userVariantColor} fillWidth inactive />;
- }
- noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Card, CollectionViewType.Carousel3D, CollectionViewType.Carousel, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
- } else {
- text = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result as string;
- // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
- if (this.Document.title === 'Font') getStyle = (val: string) => ({ fontFamily: val }); // bcz: major hack to style the font dropdown items --- needs to become part of the dropdown's metadata
- }
+ const selectedFunc = () => script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result as string;
+ const { buttonList, selectedVal, getStyle, jsx } = (() => {
+ switch (this.Document.title) {
+ case 'Font': return this.handleFontDropdown(selectedFunc, this.buttonList);
+ case 'Perspective': return this.handleViewDropdown(script, this.buttonList);
+ default: return { buttonList: this.buttonList, selectedVal: selectedFunc(), jsx: undefined, getStyle: undefined };
+ } // prettier-ignore
+ })();
+ if (jsx) return jsx;
// Get items to place into the list
- const list: IListItemProps[] = this.buttonList
- .filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value))
- .map(value => ({
- text: typeof value === 'string' ? value.charAt(0).toUpperCase() + value.slice(1) : StrCast(DocCast(value)?.title),
- val: value,
- style: getStyle(value),
- // shortcut: '#',
- }));
+ const list: IListItemProps[] = buttonList.map(value => ({
+ text: typeof value === 'string' ? value.charAt(0).toUpperCase() + value.slice(1) : StrCast(DocCast(value)?.title),
+ val: value,
+ style: getStyle?.(value),
+ // shortcut: '#',
+ }));
return (
<Dropdown
- selectedVal={text}
+ selectedVal={selectedVal}
setSelectedVal={undoable(value => script.script.run({ this: this.Document, value }), `dropdown select ${this.label}`)}
color={SnappingManager.userColor}
background={SnappingManager.userVariantColor}
@@ -215,7 +233,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
dropdownType={DropdownType.SELECT}
onItemDown={this.dropdownItemDown}
items={list}
- tooltip={this.label}
+ tooltip={StrCast(this.Document.toolTip, this.label)}
fillWidth
/>
);
@@ -235,49 +253,53 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
const tooltip: string = StrCast(this.Document.toolTip);
return (
- <ColorPicker
- setSelectedColor={value => {
- if (!this.colorBatch) this.colorBatch = UndoManager.StartBatch(`Set ${tooltip} color`);
- this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false });
- }}
- setFinalColor={value => {
- this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false });
- this.colorBatch?.end();
- this.colorBatch = undefined;
- }}
- defaultPickerType="Classic"
- selectedColor={curColor}
- type={Type.PRIM}
- color={color}
- background={SnappingManager.userBackgroundColor}
- icon={this.Icon(color) ?? undefined}
- tooltip={tooltip}
- label={this.label}
- />
+ <div
+ onPointerDown={e => {
+ e.stopPropagation();
+ }}>
+ <ColorPicker
+ setSelectedColor={value => {
+ if (!this.colorBatch) this.colorBatch = UndoManager.StartBatch(`Set ${tooltip} color`);
+ this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false });
+ }}
+ setFinalColor={value => {
+ this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false });
+ this.colorBatch?.end();
+ this.colorBatch = undefined;
+ }}
+ defaultPickerType="Classic"
+ selectedColor={curColor}
+ type={Type.PRIM}
+ color={color}
+ background={SnappingManager.userBackgroundColor}
+ icon={this.Icon(color) ?? undefined}
+ tooltip={tooltip}
+ label={this.label}
+ />
+ </div>
);
}
@computed get multiToggleButton() {
- // Determine the type of toggle button
- const tooltip: string = StrCast(this.Document.toolTip);
+ const tooltip = StrCast(this.Document.toolTip);
const script = ScriptCast(this.Document.onClick)?.script;
const toggleStatus = script?.run({ this: this.Document, value: undefined, _readOnly_: true }).result as boolean;
- // Colors
+
const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string;
- const background = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string;
const items = DocListCast(this.dataDoc.data);
const selectedItems = items.filter(itemDoc => ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, value: undefined, _readOnly_: true }).result).map(item => StrCast(item.toolType));
+
return (
<MultiToggle
- tooltip={`Toggle ${tooltip}`}
+ tooltip={`Click to Toggle ${tooltip} or select new option`}
type={Type.PRIM}
color={color}
- background={background === SnappingManager.userBackgroundColor ? undefined : background}
+ background={undefined}
multiSelect={true}
onPointerDown={e => script && !toggleStatus && setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => script.run({ this: this.Document, value: undefined, _readOnly_: false }))}
isToggle={false}
toggleStatus={toggleStatus}
- label={this.label}
+ label={selectedItems.length === 1 ? selectedItems[0] : this.label}
items={items.map(item => ({
icon: <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={StrCast(item.icon) as IconProp} color={color} />,
tooltip: StrCast(item.toolTip),
@@ -290,7 +312,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
// it would be better to pas the 'added' flag to the callback script, but our script generator from currentUserUtils makes it hard to define
// arbitrary parameter variables (but it could be done as a special case or with additional effort when creating the sript)
const itemsChanged = items.filter(item => (val instanceof Array ? val.includes(item.toolType as string | number) : item.toolType === val));
- itemsChanged.forEach(itemDoc => ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, _added_: added, itemDoc, _readOnly_: false }));
+ itemsChanged.forEach(itemDoc => ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, _added_: added, value: toggleStatus, itemDoc, _readOnly_: false }));
}}
/>
);
@@ -308,17 +330,19 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
const toggleStatus = (script?.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result as boolean) ?? false;
// Colors
const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string;
- // const backgroundColor = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor);
+ // bcz: ink shapes are tri-state - off, one-shot, and on. Need to update Toggle buttons to allow this and update currentUserUtils to set the tri-state on the Doc
+ // in the meantime, if the button matches a tool type that is not locked, we want to set the background color to something distinct.
+ const inkShapeHack = ((this.Document.toolType && this.Document.toolType === SnappingManager.InkShape) || this.Document.toolType === Doc.ActiveTool) && !SnappingManager.KeepGestureMode;
return (
<Toggle
tooltip={`Toggle ${tooltip}`}
toggleType={ToggleType.BUTTON}
- type={Type.PRIM}
+ type={inkShapeHack ? Type.TERT : Type.PRIM}
toggleStatus={toggleStatus}
text={buttonText}
color={color}
- // background={SnappingManager.userBackgroundColor}
+ background={inkShapeHack ? DashColor(SnappingManager.userBackgroundColor).darken(0.05).toString() : undefined}
icon={this.Icon(color)!}
label={this.label}
onPointerDown={e =>
@@ -392,7 +416,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
render() {
return (
- <div style={{ margin: 'auto', width: '100%' }} onContextMenu={this.specificContextMenu}>
+ <div className="fonticonbox" onContextMenu={this.specificContextMenu}>
{this.renderButton()}
</div>
);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 0dfc0ec28..ff879a2ab 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -338,7 +338,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@computed get nativeSize() {
TraceMobx();
- if (this.paths.length && this.paths[0].includes('icon-hi')) return { nativeWidth: NumCast(this.layoutDoc._width), nativeHeight: NumCast(this.layoutDoc._height), nativeOrientation: 0}
+ if (this.paths.length && this.paths[0].includes('icon-hi')) return { nativeWidth: NumCast(this.layoutDoc._width), nativeHeight: NumCast(this.layoutDoc._height), nativeOrientation: 0 };
const nativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth'], 500));
const nativeHeight = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc[this.fieldKey + '_nativeHeight'], 500));
const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + '_nativeOrientation'], 1);
@@ -465,13 +465,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
marqueeDown = (e: React.PointerEvent) => {
if (!this.dataDoc[this.fieldKey]) {
this.chooseImage();
- } else if (
- !e.altKey &&
- e.button === 0 &&
- NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) &&
- this._props.isContentActive() &&
- ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)
- ) {
+ } else if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive() && Doc.ActiveTool !== InkTool.Ink) {
setupMoveUpEvents(
this,
e,
diff --git a/src/client/views/nodes/LabelBox.scss b/src/client/views/nodes/LabelBox.scss
index ca4b3d467..889cdc0ca 100644
--- a/src/client/views/nodes/LabelBox.scss
+++ b/src/client/views/nodes/LabelBox.scss
@@ -13,7 +13,6 @@
height: 100%;
border-radius: inherit;
//letter-spacing: 2px; // bcz: doesn't work with LabelBigText
- text-transform: uppercase;
overflow: hidden;
display: inline-block;
margin: auto;
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 94a9541f2..dcf9e1fed 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -1,19 +1,22 @@
import { Property } from 'csstype';
-import { action, computed, makeObservable } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import * as textfit from 'textfit';
-import { Field, FieldType } from '../../../fields/Doc';
-import { BoolCast, NumCast, StrCast } from '../../../fields/Types';
+import { Doc, Field } from '../../../fields/Doc';
+import { NumCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
import { DocumentType } from '../../documents/DocumentTypes';
import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
+import { undoable } from '../../util/UndoManager';
import { ViewBoxBaseComponent } from '../DocComponent';
import { PinDocView, PinProps } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { FieldView, FieldViewProps } from './FieldView';
import './LabelBox.scss';
+import { FormattedTextBox } from './formattedText/FormattedTextBox';
+import { RichTextMenu } from './formattedText/RichTextMenu';
@observer
export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -22,7 +25,8 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
private dropDisposer?: DragManager.DragDropDisposer;
private _timeout: NodeJS.Timeout | undefined;
- _divRef: HTMLDivElement | null = null;
+ private _divRef: HTMLDivElement | null = null;
+ private _reaction: IReactionDisposer | undefined;
constructor(props: FieldViewProps) {
super(props);
@@ -36,21 +40,29 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
};
- @computed get Title() {
- return Field.toString(this.dataDoc[this.fieldKey] as FieldType) || StrCast(this.Document.title);
- }
-
- @computed get backgroundColor() {
- return this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string;
- }
-
componentDidMount() {
this._props.setContentViewBox?.(this);
+ this._reaction = reaction(
+ () => this.Title,
+ () => document.activeElement !== this._divRef && this._forceRerender++
+ );
}
componentWillUnMount() {
this._timeout && clearTimeout(this._timeout);
+ this.setText(this._divRef?.innerText ?? '');
+ this._reaction?.();
}
+ @observable _forceRerender = 0;
+
+ @computed get Title() { return Field.toString(this.dataDoc[this.fieldKey]); } // prettier-ignore
+ @computed get backgroundColor() { return this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string; } // prettier-ignore
+ @computed get boxShadow() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BoxShadow) as string; } // prettier-ignore
+
+ setText = undoable((text: string) => {
+ this.dataDoc[this.fieldKey] = text;
+ }, 'set label text');
+
drop = (/* e: Event, de: DragManager.DropEvent */) => {
return false;
};
@@ -82,10 +94,11 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
const textfitParams = {
minFontSize: NumCast(this.layoutDoc._label_minFontSize, 1),
maxFontSize: NumCast(this.layoutDoc._label_maxFontSize, 100),
- multiLine: BoolCast(this.layoutDoc._singleLine, true) ? false : true,
- alignHoriz: true,
+ multiLine: r?.textContent?.includes('\n') ? true : false,
+ // hack because tetFit doesn't support align 'right', but we need mobx to invalidate, so treat null as false and set to right inline
+ alignHoriz: StrCast(this.layoutDoc[this.fieldKey + '_align']) === 'center' ? true : StrCast(this.layoutDoc[this.fieldKey + '_align']) === 'right' ? (null as unknown as boolean) : false,
alignVert: true,
- detectMultiLine: true,
+ detectMultiLine: false,
};
if (r) {
if (!r.offsetHeight || !r.offsetWidth) {
@@ -94,65 +107,140 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
this._timeout = setTimeout(() => this.fitTextToBox(r));
return textfitParams;
}
+ r.style.whiteSpace = ''; // textfit sets to nowrap if not multiline, but doesn't reeset if it becomes multiline
+ r.style.textAlign = StrCast(this.layoutDoc[this.fieldKey + '_align']); // textfit doesn't reset textAlign if it has been set to center, so we just set it to what we want
+ r.firstChild instanceof HTMLElement && (r.firstChild.style.textAlign = StrCast(this.layoutDoc[this.fieldKey + '_align']));
textfit(r, textfitParams);
}
return textfitParams;
};
+ resetCursor = (cranchor?: number) => {
+ if (this._divRef && (cranchor || this._divRef === document.activeElement)) {
+ const range = document.createRange();
+ const anchor = cranchor ?? this._divRef.childNodes.length;
+ const container = cranchor === undefined ? this._divRef : (this._divRef.firstChild?.firstChild ?? this._divRef);
+ range.setStart(container, anchor);
+ range.setEnd(container, anchor);
+ const sel = window.getSelection();
+ sel?.removeAllRanges();
+ sel?.addRange(range);
+ }
+ };
+
+ beforeInput = action((event: InputEvent) => {
+ const spanChild = this._divRef?.firstChild?.firstChild;
+ if (spanChild?.nodeName === '#text' && ['insertLineBreak', 'insertParagraph'].includes(event.inputType)) {
+ event.preventDefault();
+ event.stopPropagation();
+
+ const selection = document.getSelection();
+ if (selection && document.activeElement === event.target) {
+ const text = spanChild.textContent ?? '';
+ const cranchor = selection.anchorNode === this._divRef ? (selection.anchorOffset ? text.length : 0) : selection.anchorOffset;
+ const addReturnHack = text.length <= cranchor && text[text.length - 1] !== '\n' ? '\n\n' : '\n'; // not sure why, but need to add a second carriage return if typing enter at the end of the text
+ const splitText = text.substring(0, cranchor) + addReturnHack + text.substring(cranchor);
+ spanChild.textContent = splitText;
+ this.resetCursor(cranchor + addReturnHack.length);
+ }
+ // const span = document.createElement('span');
+ // span.innerHTML = '&#8203;';
+ // this._divRef!.append(span);
+ }
+ });
+ // .labelBox-mainButton > div > span:nth-child(2) {
+
+ /**
+ * When an IconButton is clicked, it will receive focus. However, we don't want that since we want or need that since we really want
+ * to maintain focus in the label's editing div (and cursor position). so this relies on IconButton's having a tabindex set to -1 so that
+ * we can march up the tree from the 'relatedTarget' to determine if the loss of focus was caused by a fonticonbox. If it is, we then
+ * restore focus
+ * @param e focusout event on the editing div
+ */
+ keepFocus = (e: FocusEvent) => {
+ if (e.relatedTarget instanceof HTMLElement && e.relatedTarget.tabIndex === -1) {
+ for (let ele: HTMLElement | null = e.relatedTarget; ele; ele = (ele as HTMLElement)?.parentElement) {
+ if ((ele as HTMLElement)?.className === 'fonticonbox') {
+ setTimeout(() => this._divRef?.focus());
+ break;
+ }
+ }
+ }
+ };
+
render() {
TraceMobx();
const boxParams = this.fitTextToBox(undefined); // this causes mobx to trigger re-render when data changes
- const label = this.Title.startsWith('#') ? null : this.Title;
return (
- <div key={label?.length} className="labelBox-outerDiv" ref={this.createDropTarget} style={{ boxShadow: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BoxShadow) as string }}>
+ <div className="labelBox-outerDiv" ref={this.createDropTarget} style={{ boxShadow: this.boxShadow }}>
<div
className="labelBox-mainButton"
style={{
backgroundColor: this.backgroundColor,
- // fontSize: StrCast(this.layoutDoc._text_fontSize),
- color: StrCast(this.layoutDoc._color),
- fontFamily: StrCast(this.layoutDoc._text_fontFamily) || 'inherit',
+ color: StrCast(this.layoutDoc._text_fontColor, StrCast(this.layoutDoc._color)),
+ fontFamily: StrCast(this.layoutDoc._text_fontFamily, StrCast(Doc.UserDoc().fontFamily)) || 'inherit',
letterSpacing: StrCast(this.layoutDoc.letterSpacing),
- textTransform: StrCast(this.layoutDoc.textTransform) as Property.TextTransform,
+ textTransform: StrCast(this.layoutDoc[this.fieldKey + '_transform']) as Property.TextTransform,
paddingLeft: NumCast(this.layoutDoc._xPadding),
paddingRight: NumCast(this.layoutDoc._xPadding),
paddingTop: NumCast(this.layoutDoc._yPadding),
paddingBottom: NumCast(this.layoutDoc._yPadding),
width: this._props.PanelWidth(),
height: this._props.PanelHeight(),
- whiteSpace: 'multiLine' in boxParams && boxParams.multiLine ? 'pre-wrap' : 'pre',
+ whiteSpace: boxParams.multiLine ? 'pre-wrap' : 'pre',
}}>
<div
+ key={this._forceRerender}
style={{
width: this._props.PanelWidth() - 2 * NumCast(this.layoutDoc._xPadding),
height: this._props.PanelHeight() - 2 * NumCast(this.layoutDoc._yPadding),
outline: 'unset !important',
}}
- onKeyDown={action(e => {
+ onKeyDown={e => {
e.stopPropagation();
- })}
+ }}
onKeyUp={action(e => {
e.stopPropagation();
- this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? '';
- setTimeout(() => this._props.select(false));
+ const text = this._divRef?.firstChild;
+ if (text && (text as HTMLElement)?.nodeType === 3) {
+ this._divRef?.removeChild(text);
+ this._divRef?.firstChild?.appendChild(text);
+ this.resetCursor();
+ }
+ this.fitTextToBox(this._divRef);
})}
+ onFocus={() => {
+ RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, this.dataDoc);
+ this._divRef?.removeEventListener('focusout', this.keepFocus);
+ this._divRef?.addEventListener('focusout', this.keepFocus);
+ }}
onBlur={() => {
- this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? '';
+ this._divRef?.removeEventListener('focusout', this.keepFocus);
+ this.setText(this._divRef?.innerText ?? '');
+ RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, undefined);
+ FormattedTextBox.LiveTextUndo?.end();
+ FormattedTextBox.LiveTextUndo = undefined;
+ }}
+ dangerouslySetInnerHTML={{
+ __html: `<span class="textFitted textFitAlignVert" style="display: inline-block; text-align: center; font-size: 100px; height: 0px;">${this.Title.startsWith('#') ? null : (this.Title ?? '')}</span>`,
}}
contentEditable={this._props.onClickScript?.() ? undefined : true}
ref={r => {
+ this._divRef?.removeEventListener('beforeinput', this.beforeInput);
this._divRef = r;
- this.fitTextToBox(r);
- if (this._props.isSelected() && this._divRef) {
- const range = document.createRange();
- range.setStart(this._divRef, this._divRef.childNodes.length);
- range.setEnd(this._divRef, this._divRef.childNodes.length);
- const sel = window.getSelection();
- sel?.removeAllRanges();
- sel?.addRange(range);
+ if (this._divRef) {
+ this._divRef.addEventListener('beforeinput', this.beforeInput);
+
+ if (Doc.SelectOnLoad === this.Document) {
+ Doc.SelectOnLoad = undefined;
+ this._divRef.focus();
+ }
+ this.fitTextToBox(this._divRef);
+ if (this.Title) {
+ this.resetCursor();
+ }
}
- }}>
- {label}
- </div>
+ }}
+ />
</div>
</div>
);
@@ -161,9 +249,9 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
Docs.Prototypes.TemplateMap.set(DocumentType.LABEL, {
layout: { view: LabelBox, dataField: 'title' },
- options: { acl: '', _singleLine: true, _layout_nativeDimEditable: true, _layout_reflowHorizontal: true, _layout_reflowVertical: true },
+ options: { acl: '', _layout_nativeDimEditable: true, _layout_reflowHorizontal: true, _layout_reflowVertical: true, title_align: 'center', title_transform: 'uppercase' },
});
Docs.Prototypes.TemplateMap.set(DocumentType.BUTTON, {
layout: { view: LabelBox, dataField: 'title' },
- options: { acl: '', _layout_nativeDimEditable: true, _layout_reflowHorizontal: true, _layout_reflowVertical: true },
+ options: { acl: '', _layout_nativeDimEditable: true, _layout_reflowHorizontal: true, _layout_reflowVertical: true, title_align: 'center', title_transform: 'uppercase' },
});
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index c66f7c726..4a436319b 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -428,7 +428,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
};
- getView = async (doc: Doc, options: FocusViewOptions) => {
+ getView = (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
this.toggleSidebar();
options.didMove = true;
diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
index a4557196e..d5d8f8afa 100644
--- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
+++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
@@ -383,7 +383,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<FieldViewProps>
}
};
- getView = async (doc: Doc, options: FocusViewOptions) => {
+ getView = (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
this.toggleSidebar();
options.didMove = true;
@@ -732,7 +732,6 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<FieldViewProps>
MapBoxContainer._rerenderDelay = 0;
}
this._rerenderTimeout = undefined;
- // eslint-disable-next-line operator-assignment
this.Document[DocCss] = this.Document[DocCss] + 1;
}), MapBoxContainer._rerenderDelay);
return null;
@@ -792,7 +791,6 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<FieldViewProps>
.map(pushpin => (
<DocumentView
key={pushpin[Id]}
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
renderDepth={this._props.renderDepth + 1}
Document={pushpin}
@@ -830,7 +828,6 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<FieldViewProps>
<div className="mapBox-sidebar" style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
<SidebarAnnos
ref={this._sidebarRef}
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
fieldKey={this.fieldKey}
Document={this.Document}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 816d4a3b0..2e4c87d38 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -233,7 +233,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.y, NumCast(anchor.config_scrollTop)), options);
};
- getView = async (doc: Doc, options: FocusViewOptions) => {
+ getView = (doc: Doc, options: FocusViewOptions) => {
if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) {
options.didMove = true;
this.toggleSidebar(false);
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index de51f6447..3bf7de2fe 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -776,7 +776,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// starts marquee selection
marqueeDown = (e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive() && Doc.ActiveTool !== InkTool.Ink) {
setupMoveUpEvents(
this,
e,
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index a5788d02a..9ba4f8ead 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -44,6 +44,7 @@ import { LinkInfo } from './LinkDocPreview';
import { OpenWhere } from './OpenWhere';
import './WebBox.scss';
+// eslint-disable-next-line @typescript-eslint/no-require-imports
const { CreateImage } = require('./WebBoxRenderer');
@observer
@@ -335,7 +336,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
ele = document.createElement('div');
ele.append(contents);
}
- } catch (e) {
+ } catch {
/* empty */
}
const visibleAnchor = this._getAnchor(this._savedAnnotations, true);
@@ -506,7 +507,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
let href: Opt<string>;
try {
href = iframe?.contentWindow?.location.href;
- } catch (e) {
+ } catch {
runInAction(() => this._warning++);
href = undefined;
}
@@ -713,7 +714,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._webUrl = this._url;
}
}
- } catch (e) {
+ } catch {
console.log('WebBox URL error:' + this._url);
}
return true;
@@ -805,7 +806,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
sel.empty(); // Chrome
else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox
this.marqueeing = [e.clientX, e.clientY];
- if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this._props.isContentActive() && Doc.ActiveTool !== InkTool.Ink) {
setupMoveUpEvents(
this,
e,
@@ -855,7 +856,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
})}
contentEditable
onPointerDown={this.webClipDown}
- // eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: field.html }}
/>
);
@@ -1031,7 +1031,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
{this.inlineTextAnnotations
.sort((a, b) => NumCast(a.y) - NumCast(b.y))
.map(anno => (
- // eslint-disable-next-line react/jsx-props-no-spreading
<Annotation {...this._props} fieldKey={this.annotationKey} pointerEvents={this.pointerEvents} containerDataDoc={this.dataDoc} annoDoc={anno} key={`${anno[Id]}-annotation`} />
))}
</div>
@@ -1042,7 +1041,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
renderAnnotations = (childFilters: () => string[]) => (
<CollectionFreeFormView
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
setContentViewBox={this.setInnerContent}
NativeWidth={returnZero}
@@ -1217,7 +1215,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
<div style={{ position: 'absolute', height: '100%', right: 0, top: 0, width: `calc(100 * ${this.sidebarWidth() / this._props.PanelWidth()}%` }}>
<SidebarAnnos
ref={this._sidebarRef}
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
fieldKey={this.fieldKey + '_' + this._urlHash}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 29be8d285..905c69bb8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -65,6 +65,7 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu';
import { RichTextRules } from './RichTextRules';
import { schema } from './schema_rts';
import { Property } from 'csstype';
+import { LabelBox } from '../LabelBox';
// import * as applyDevTools from 'prosemirror-dev-tools';
export interface FormattedTextBoxProps extends FieldViewProps {
@@ -134,10 +135,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
@observable _showSidebar = false;
- @computed get fontColor() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontColor) as string; } // prettier-ignore
- @computed get fontSize() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontSize) as string; } // prettier-ignore
- @computed get fontFamily() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontFamily) as string; } // prettier-ignore
- @computed get fontWeight() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontWeight) as string; } // prettier-ignore
+ @computed get fontColor() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontColor) as string; } // prettier-ignore
+ @computed get fontSize() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontSize) as string; } // prettier-ignore
+ @computed get fontFamily() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontFamily) as string; } // prettier-ignore
+ @computed get fontWeight() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontWeight) as string; } // prettier-ignore
+ @computed get fontStyle() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontStyle) as string; } // prettier-ignore
+ @computed get fontDecoration() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontDecoration) as string; } // prettier-ignore
set _recordingDictation(value) {
!this.dataDoc[`${this.fieldKey}_recordingSource`] && (this.dataDoc.mediaState = value ? mediaState.Recording : undefined);
@@ -158,6 +161,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
@computed get titleHeight() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin) as number || 0; } // prettier-ignore
@computed get layout_autoHeightMargins() { return this.titleHeight + NumCast(this.layoutDoc._layout_autoHeightMargins); } // prettier-ignore
@computed get sidebarKey() { return this.fieldKey + '_sidebar'; } // prettier-ignore
+ @computed get isLabel() { return this.dataDoc[this.fieldKey+"_fitBox"]; } // prettier-ignore
constructor(props: FormattedTextBoxProps) {
super(props);
@@ -165,7 +169,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
this._recordingStart = Date.now();
}
- public get EditorView() { return this._editorView; } // prettier-ignore
+ public get EditorView() { return this.isLabel ? undefined : this._editorView; } // prettier-ignore
// public makeAIFlashcards: () => void = unimplementedFunction;
public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined;
@@ -175,10 +179,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
// but since removing one anchor from the list of attr anchors isn't implemented, this will end up removing nothing.
public RemoveLinkFromDoc(linkDoc?: Doc) {
this.unhighlightSearchTerms();
- const state = this._editorView?.state;
+ const state = this.EditorView?.state;
const a1 = DocCast(linkDoc?.link_anchor_1);
const a2 = DocCast(linkDoc?.link_anchor_2);
- if (state && a1 && a2 && this._editorView) {
+ if (state && a1 && a2 && this.EditorView) {
this.removeDocument(a1);
this.removeDocument(a2);
let allFoundLinkAnchors: { href: string; title: string; anchorId: string }[] = [];
@@ -188,7 +192,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return true;
});
if (allFoundLinkAnchors.length) {
- this._editorView.dispatch(removeMarkWithAttrs(state.tr, 0, state.doc.nodeSize - 2, state.schema.marks.linkAnchor, { allAnchors: allFoundLinkAnchors }));
+ this.EditorView.dispatch(removeMarkWithAttrs(state.tr, 0, state.doc.nodeSize - 2, state.schema.marks.linkAnchor, { allAnchors: allFoundLinkAnchors }));
this.setupEditor(this.config, this.fieldKey);
}
@@ -197,16 +201,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
// removes all the specified link references from the selection.
// NOTE: as above, this won't work correctly if there are marks with overlapping but not exact sets of link references.
public RemoveAnchorFromSelection(allAnchors: { href: string; title: string; linkId: string; targetId: string }[]) {
- const state = this._editorView?.state;
- if (state && this._editorView) {
- this._editorView.dispatch(removeMarkWithAttrs(state.tr, state.selection.from, state.selection.to, state.schema.marks.link, { allAnchors }));
+ const state = this.EditorView?.state;
+ if (state && this.EditorView) {
+ this.EditorView.dispatch(removeMarkWithAttrs(state.tr, state.selection.from, state.selection.to, state.schema.marks.link, { allAnchors }));
this.setupEditor(this.config, this.fieldKey);
}
}
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
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;
+ if (!pinProps && this.EditorView?.state.selection.empty) return rootDoc;
const anchor = Docs.Create.ConfigDocument({ title: StrCast(rootDoc.title), annotationOn: rootDoc });
this.addDocument(anchor);
this._finishingLink = true;
@@ -263,7 +267,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
});
};
- AnchorMenu.Instance.Highlight = undoable((color: string) => this._editorView?.state && RichTextMenu.Instance?.setFontField(color, 'fontHighlight'), 'highlght text');
+ AnchorMenu.Instance.Highlight = undoable((color: string) => this.EditorView?.state && RichTextMenu.Instance?.setFontField(color, 'fontHighlight'), 'highlght text');
AnchorMenu.Instance.onMakeAnchor = () => this.getAnchor(true);
AnchorMenu.Instance.StartCropDrag = unimplementedFunction;
/**
@@ -292,7 +296,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
AnchorMenu.Instance.setSelectedText(window.getSelection()?.toString() ?? '');
- const coordsB = this._editorView!.coordsAtPos(this._editorView!.state.selection.to);
+ const coordsB = this.EditorView!.coordsAtPos(this.EditorView!.state.selection.to);
this._props.rootSelected?.() && AnchorMenu.Instance.jumpTo(coordsB.left, coordsB.bottom);
let ele: Opt<HTMLDivElement>;
try {
@@ -309,7 +313,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
leafText = (node: Node) => {
- if (node.type === this._editorView?.state.schema.nodes.dashField) {
+ if (node.type === this.EditorView?.state.schema.nodes.dashField) {
const refDoc = !node.attrs.docId ? DocCast(this.Document.rootDocument, this.Document) : (DocServer.GetCachedRefField(node.attrs.docId as string) as Doc);
const fieldKey = StrCast(node.attrs.fieldKey);
return (
@@ -320,16 +324,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return '';
};
dispatchTransaction = (tx: Transaction) => {
- if (this._editorView && !this._editorView.isDestroyed) {
- const state = this._editorView.state.apply(tx);
- this._editorView.updateState(state);
+ if (this.EditorView && !this.EditorView.isDestroyed) {
+ const state = this.EditorView.state.apply(tx);
+ this.EditorView.updateState(state);
this.tryUpdateDoc(false);
}
};
tryUpdateDoc = (force: boolean) => {
- if (this._editorView) {
- const { state } = this._editorView;
+ 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());
@@ -372,7 +376,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
textChange && (dataDoc[this.fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())));
// if we've deleted all the text in a note driven by a template, then restore the template data
dataDoc[this.fieldKey] = undefined;
- this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse(rtField.Data)));
+ this.EditorView.updateState(EditorState.fromJSON(this.config, JSON.parse(rtField.Data)));
ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, text: newText });
unchanged = false;
}
@@ -387,7 +391,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (jsonstring) {
const json = JSON.parse(jsonstring);
json.selection = state.toJSON().selection;
- this._editorView.updateState(EditorState.fromJSON(this.config, json));
+ this.EditorView.updateState(EditorState.fromJSON(this.config, json));
}
}
if (window.getSelection()?.isCollapsed && this._props.rootSelected?.()) {
@@ -407,8 +411,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
linkAnchor = anchor;
}
});
- if (this._editorView && linkTime) {
- const { state } = this._editorView;
+ if (this.EditorView && linkTime) {
+ const { state } = this.EditorView;
const node = state.selection.$from.node();
if (linkAnchor && node.type !== state.schema.nodes.code_block) {
const time = linkTime + Date.now() / 1000 - this._recordingStart / 1000;
@@ -416,7 +420,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
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))));
+ this.EditorView.dispatch(replaced.setSelection(new TextSelection(replaced.doc.resolve(from + 1))));
}
}
};
@@ -431,16 +435,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
(Doc.isTemplateForField(this.Document) && (link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document))) &&
link.link_relationship === LinkManager.AutoKeywords
); // prettier-ignore
- if (this._editorView?.state.doc.textContent) {
- let { tr } = this._editorView.state;
- const { from, to } = this._editorView.state.selection;
- const { autoLinkAnchor } = this._editorView.state.schema.marks;
+ if (this.EditorView?.state.doc.textContent) {
+ 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);
+ this.EditorView?.dispatch(tr);
}
oldAutoLinks.filter(oldLink => !newAutoLinks.has(oldLink) && oldLink.link_anchor_2 !== this.Document).forEach(doc => Doc.DeleteLink?.(doc));
};
@@ -450,11 +454,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (
!this._props.dontRegisterView && // (this.Document.isTemplateForField === "text" || !this.Document.isTemplateForField) && // only update the title if the data document's data field is changing
title.startsWith('-') &&
- this._editorView &&
+ this.EditorView &&
!this.dataDoc.title_custom &&
(Doc.LayoutFieldKey(this.Document) === this.fieldKey || this.fieldKey === 'text')
) {
- let node = this._editorView.state.doc;
+ let node = this.EditorView.state.doc;
while (node.firstChild && node.firstChild.type.name !== 'text') node = node.firstChild;
const str = node.textContent;
const prefix = '-';
@@ -477,7 +481,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
*/
hyperlinkTerm = (trIn: Transaction, target: Doc, newAutoLinks: Set<Doc>) => {
let tr = trIn;
- const editorView = this._editorView;
+ const editorView = this.EditorView;
if (editorView && !Doc.AreProtosEqual(target, this.Document)) {
const autoLinkTerm = Field.toString(target.title as FieldType).replace(/^@/, '');
let alink: Doc | undefined;
@@ -553,18 +557,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
unhighlightSearchTerms = () => {
- if (this._editorView) {
- const { state } = this._editorView;
+ 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));
+ this.EditorView.dispatch(state.tr.removeMark(0, end, mark).removeMark(0, end, activeMark));
}
}
};
adoptAnnotation = (start: number, end: number, mark: Mark) => {
- const view = this._editorView!;
+ const view = this.EditorView!;
const nmark = view.state.schema.marks.user_mark.create({ ...mark.attrs, userid: ClientUtils.CurrentUserEmail() });
view.dispatch(view.state.tr.removeMark(start, end, nmark).addMark(start, end, nmark));
};
@@ -616,7 +620,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (added) {
draggedDoc._freeform_fitContentsToBox = true;
Doc.SetContainer(draggedDoc, this.Document);
- const view = this._editorView!;
+ const view = this.EditorView!;
try {
this._inDrop = true;
const pos = view.posAtCoords({ left: de.x, top: de.y })?.pos;
@@ -810,7 +814,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
let target: Element | HTMLElement | null = e.target as HTMLElement; // hrefs are stored on the database of the <a> node that wraps the hyerlink <span>
while (target && (!(target instanceof HTMLElement) || !target.dataset?.targethrefs)) target = target.parentElement;
- const editor = this._editorView;
+ const editor = this.EditorView;
if (editor && target && !(e.nativeEvent instanceof simMouseEvent ? e.nativeEvent.dash : false)) {
const hrefs = (target.dataset?.targethrefs as string)
?.trim()
@@ -996,8 +1000,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const c = this.ProseRef?.getElementsByTagName('img');
if (c) {
for (const i of c) {
- console.log(i);
-
// console.log(canvas.toDataURL());
// canvas.style.zIndex = '2000000';
// document.body.appendChild(canvas);
@@ -1022,8 +1024,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
animateRes = (resIndex: number, newText: string) => {
if (resIndex < newText.length) {
- const marks = this._editorView?.state.storedMarks ?? [];
- this._editorView?.dispatch(this._editorView?.state.tr.insertText(newText[resIndex]).setStoredMarks(marks));
+ const marks = this.EditorView?.state.storedMarks ?? [];
+ this.EditorView?.dispatch(this.EditorView?.state.tr.insertText(newText[resIndex]).setStoredMarks(marks));
setTimeout(() => this.animateRes(resIndex + 1, newText), 20);
}
};
@@ -1035,8 +1037,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const res = await gptAPICall((this.dataDoc.text as RichTextField)?.Text, GPTCallType.COMPLETION);
if (!res) {
this.animateRes(0, 'Something went wrong.');
- } else if (this._editorView) {
- const { dispatch, state } = this._editorView;
+ } else if (this.EditorView) {
+ const { dispatch, state } = this.EditorView;
// for no animation, use: dispatch(state.tr.insertText(res));
// for animted response starting at end of text, use:
dispatch(state.tr.setSelection(Selection.atEnd(state.doc)));
@@ -1057,13 +1059,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
breakupDictation = () => {
- if (this._editorView && this._recordingDictation) {
+ if (this.EditorView && this._recordingDictation) {
this.stopDictation(/* true */);
this._break = true;
- const { state } = this._editorView;
+ 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({})));
+ this.EditorView.dispatch(state.tr.setSelection(updated).insert(to, state.schema.nodes.paragraph.create({})));
if (this._recordingDictation) {
this.recordDictation();
}
@@ -1082,7 +1084,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
stopDictation = (/* abort: boolean */) => DictationManager.Controls.stop(/* !abort */);
setDictationContent = (value: string) => {
- if (this._editorView && this._recordingStart) {
+ if (this.EditorView && this._recordingStart) {
if (this._break) {
const textanchorFunc = () => {
const tanch = Docs.Create.ConfigDocument({ title: 'dictation anchor' });
@@ -1095,22 +1097,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const textanchor = Cast(link.link_anchor_1, Doc, null);
if (audioanchor) {
audioanchor.backgroundColor = 'tan';
- const audiotag = this._editorView.state.schema.nodes.audiotag.create({
+ const audiotag = this.EditorView.state.schema.nodes.audiotag.create({
timeCode: NumCast(audioanchor._timecodeToShow),
audioId: audioanchor[Id],
textId: textanchor[Id],
});
textanchor[DocData].title = 'dictation:' + audiotag.attrs.timeCode;
- const tr = this._editorView.state.tr.insert(this._editorView.state.doc.content.size, audiotag);
+ const tr = this.EditorView.state.tr.insert(this.EditorView.state.doc.content.size, audiotag);
const tr2 = tr.setSelection(TextSelection.create(tr.doc, tr.doc.content.size));
- this._editorView.dispatch(tr.setSelection(TextSelection.create(tr2.doc, tr2.doc.content.size)));
+ this.EditorView.dispatch(tr.setSelection(TextSelection.create(tr2.doc, tr2.doc.content.size)));
}
}
}
- const { from } = this._editorView.state.selection;
+ 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());
+ const tr = this.EditorView.state.tr.insertText(value);
+ this.EditorView.dispatch(tr.setSelection(TextSelection.create(tr.doc, from, tr.doc.content.size)).scrollIntoView());
}
};
@@ -1143,7 +1145,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(selection.from, selection.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;
@@ -1156,7 +1158,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return anchorDoc ?? this.Document;
}
- getView = async (doc: Doc, options: FocusViewOptions) => {
+ getView = (doc: Doc, options: FocusViewOptions) => {
if (DocListCast(this.dataDoc[this.sidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) {
if (!this.SidebarShown) {
this.toggleSidebar(false);
@@ -1177,7 +1179,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
let hadStart = start !== 0;
frag.forEach((node, index) => {
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)) {
+ 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);
!hadStart && (start = index + examinedNode.start);
hadStart = true;
@@ -1186,13 +1188,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return { frag: Fragment.fromArray(nodes), start };
};
const findAnchorNode = (node: Node, editor: EditorView) => {
- if (node.type === this._editorView?.state.schema.nodes.audiotag) {
+ if (node.type === this.EditorView?.state.schema.nodes.audiotag) {
if (node.attrs.textId === textAnchorId) {
return { node, start: 0 };
}
return undefined;
}
- if (node.type === this._editorView?.state.schema.nodes.dashDoc) {
+ if (node.type === this.EditorView?.state.schema.nodes.dashDoc) {
if (node.attrs.docId === textAnchorId) {
return { node, start: 0 };
}
@@ -1208,9 +1210,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
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 { state } = this._editorView;
- const ret = findAnchorFrag(state.doc.content, this._editorView);
+ if (this.EditorView && textAnchorId) {
+ const { state } = this.EditorView;
+ const ret = findAnchorFrag(state.doc.content, this.EditorView);
const firstChild = ret.frag.childCount ? ret.frag.child(0) : undefined;
if (ret.start >= 0 && (ret.frag.size || (firstChild && [state.schema.nodes.dashDoc, state.schema.nodes.audioTag].includes(firstChild.type)))) {
@@ -1219,7 +1221,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (ret.frag.firstChild) {
selection = TextSelection.between(state.doc.resolve(ret.start), state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected
}
- this._editorView.dispatch(state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView());
+ this.EditorView.dispatch(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(() => {
@@ -1307,15 +1309,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return !whichData ? undefined : { data: RTFCast(whichData), str: Field.toString(DocCast(whichData) ?? StrCast(whichData)) };
},
incomingValue => {
- if (this._editorView && this._applyingChange !== this.fieldKey) {
+ if (this.EditorView && this._applyingChange !== this.fieldKey) {
if (incomingValue?.data) {
const updatedState = JSON.parse(incomingValue.data.Data);
- if (JSON.stringify(this._editorView.state.toJSON()) !== JSON.stringify(updatedState)) {
- this._editorView.updateState(EditorState.fromJSON(this.config, updatedState));
+ if (JSON.stringify(this.EditorView.state.toJSON()) !== JSON.stringify(updatedState)) {
+ this.EditorView.updateState(EditorState.fromJSON(this.config, updatedState));
this.tryUpdateScrollHeight();
}
- } else if (this._editorView.state.doc.textContent !== incomingValue?.str) {
- selectAll(this._editorView.state, tx => this._editorView?.dispatch(tx.insertText(incomingValue?.str ?? '')));
+ } else if (this.EditorView.state.doc.textContent !== (incomingValue?.str ?? '')) {
+ selectAll(this.EditorView.state, tx => this.EditorView?.dispatch(tx.insertText(incomingValue?.str ?? '')));
}
}
},
@@ -1333,9 +1335,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
action(selected => {
if (selected && this.dataDoc[this.fieldKey + '_placeholder']) {
setTimeout(() => {
- selectAll(this._editorView!.state, (tx: Transaction) => {
- this._editorView?.dispatch(tx);
- this._editorView!.focus();
+ selectAll(this.EditorView!.state, (tx: Transaction) => {
+ this.EditorView?.dispatch(tx);
+ this.EditorView!.focus();
});
});
}
@@ -1343,12 +1345,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (FormattedTextBox._globalHighlights.has('Bold Text')) {
this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css change happens outside of mobx/react, so this will notify anyone interested in the layout that it has changed
}
- if (RichTextMenu.Instance?.view === this._editorView && !selected) {
+ if (((RichTextMenu.Instance?.view === this.EditorView && this.EditorView) || this.isLabel) && !selected) {
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, undefined);
}
- if (this._editorView && selected) {
- RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this._props, this.layoutDoc);
- setTimeout(this.autoLink, 20);
+ if (selected) {
+ RichTextMenu.Instance?.updateMenu(this.EditorView, undefined, this._props, this.dataDoc);
+ this.EditorView && setTimeout(this.autoLink, 20);
}
}),
{ fireImmediately: true }
@@ -1389,7 +1391,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
// DocCast(this.Document.image)._freeform_fitContentsToBox = true;
// Doc.SetContainer(DocCast(this.Document.image), this.Document);
- // const view = this._editorView!;
+ // const view = this.EditorView!;
// try {
// this._inDrop = true;
// const pos = view.posAtCoords({ left: 0, top: 0 })?.pos;
@@ -1436,7 +1438,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
addPdfReference = (pdfAnchorId: string) => {
- const view = this._editorView!;
+ const view = this.EditorView!;
if (pdfAnchorId) {
DocServer.GetRefField(pdfAnchorId).then(pdfAnchor => {
if (pdfAnchor instanceof Doc) {
@@ -1487,7 +1489,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const curText = Cast(this.dataDoc[this.fieldKey], RichTextField, null) || StrCast(this.dataDoc[this.fieldKey]);
const rtfField = Cast((!curText && this.layoutDoc[this.fieldKey]) || this.dataDoc[fieldKey], RichTextField);
if (this.ProseRef) {
- this._editorView?.destroy();
+ this.EditorView?.destroy();
this._editorView = new EditorView(this.ProseRef, {
state: rtfField?.Data ? EditorState.fromJSON(config, JSON.parse(rtfField.Data)) : EditorState.create(config),
handleScrollToSelection: editorView => {
@@ -1519,14 +1521,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (!rtfField) {
const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
const startupText = Field.toString(dataDoc[fieldKey] as FieldType);
- const textAlign = StrCast(this.dataDoc.text_align, StrCast(Doc.UserDoc().textAlign)) || 'left';
+ const textAlign = StrCast(this.dataDoc[this.fieldKey + '_align'], StrCast(Doc.UserDoc().textAlign)) || 'left';
if (textAlign !== 'left') {
selectAll(this._editorView.state, tr => {
- this._editorView?.dispatch(tr.replaceSelectionWith(state.schema.nodes.paragraph.create({ align: textAlign })));
+ this.EditorView?.dispatch(tr.replaceSelectionWith(state.schema.nodes.paragraph.create({ align: textAlign })));
});
}
if (startupText) {
- this._editorView?.dispatch(this._editorView.state.tr.insertText(startupText));
+ this.EditorView?.dispatch(this.EditorView.state.tr.insertText(startupText));
}
this.tryUpdateDoc(true);
}
@@ -1539,56 +1541,57 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
Doc.SetSelectOnLoad(undefined);
FormattedTextBox.SelectOnLoadChar = '';
}
- if (this._editorView && selectOnLoad && !this._props.dontRegisterView && !this._props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
+ if (this.EditorView && selectOnLoad && !this._props.dontRegisterView && !this._props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
this._props.select(false);
if (selLoadChar) {
- const $from = this._editorView.state.selection.anchor ? this._editorView.state.doc.resolve(this._editorView.state.selection.anchor - 1) : undefined;
+ const $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 curMarks = this.EditorView.state.storedMarks ?? $from?.marksAcross(this.EditorView.state.selection.$head) ?? [];
const storedMarks = [...curMarks.filter(m => m.type !== mark.type), mark];
- const tr1 = this._editorView.state.tr.setStoredMarks(storedMarks);
- const tr2 = selLoadChar === 'Enter' ? tr1.insert(this._editorView.state.doc.content.size - 1, schema.nodes.paragraph.create()) : tr1.insertText(selLoadChar, this._editorView.state.doc.content.size - 1);
+ const tr1 = this.EditorView.state.tr.setStoredMarks(storedMarks);
+ const tr2 = selLoadChar === 'Enter' ? tr1.insert(this.EditorView.state.doc.content.size - 1, schema.nodes.paragraph.create()) : tr1.insertText(selLoadChar, this.EditorView.state.doc.content.size - 1);
const tr = tr2.setStoredMarks(storedMarks);
- this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
+ 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 (!FormattedTextBox.DontSelectInitialText) {
const mark = schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) });
- selectAll(this._editorView.state, (tx: Transaction) => {
- this._editorView?.dispatch(tx.addStoredMark(mark));
+ selectAll(this.EditorView.state, (tx: Transaction) => {
+ this.EditorView?.dispatch(tx.addStoredMark(mark));
});
+ this.EditorView?.dispatch(this.EditorView.state.tr.setSelection(new TextSelection(this.EditorView.state.doc.resolve(1))));
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 $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 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));
+ 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) {
FormattedTextBox.DontSelectInitialText = false;
- this._editorView!.focus();
+ this.EditorView!.focus();
}
if (this._props.isContentActive()) this.prepareForTyping();
- if (this._editorView && FormattedTextBox.PasteOnLoad) {
+ if (this.EditorView && FormattedTextBox.PasteOnLoad) {
const pdfAnchorId = FormattedTextBox.PasteOnLoad.clipboardData?.getData('dash/pdfAnchor');
FormattedTextBox.PasteOnLoad = undefined;
pdfAnchorId && this.addPdfReference(pdfAnchorId);
}
- if (this._props.autoFocus) setTimeout(() => this._editorView!.focus()); // not sure why setTimeout is needed but editing dashFieldView's doesn't work without it.
+ if (this._props.autoFocus) setTimeout(() => this.EditorView!.focus()); // not sure why setTimeout is needed but editing dashFieldView's doesn't work without it.
}
// add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet.
prepareForTyping = () => {
- if (this._editorView) {
+ if (this.EditorView) {
const { text, paragraph } = schema.nodes;
- const selNode = this._editorView.state.selection.$anchor.node();
- if (this._editorView.state.selection.from === 1 && this._editorView.state.selection.empty && [undefined, text, paragraph].includes(selNode?.type)) {
+ const selNode = this.EditorView.state.selection.$anchor.node();
+ if (this.EditorView.state.selection.from === 1 && this.EditorView.state.selection.empty && [undefined, text, paragraph].includes(selNode?.type)) {
const docDefaultMarks = [schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) })];
- this._editorView.state.selection.empty && this._editorView.state.selection.from === 1 && this._editorView?.dispatch(this._editorView?.state.tr.setStoredMarks(docDefaultMarks).removeStoredMark(schema.marks.pFontColor));
+ this.EditorView.state.selection.empty && this.EditorView.state.selection.from === 1 && this.EditorView?.dispatch(this.EditorView?.state.tr.setStoredMarks(docDefaultMarks).removeStoredMark(schema.marks.pFontColor));
}
}
};
@@ -1602,7 +1605,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
FormattedTextBox.LiveTextUndo?.end();
FormattedTextBox.LiveTextUndo = undefined;
this.unhighlightSearchTerms();
- this._editorView?.destroy();
+ this.EditorView?.destroy();
RichTextMenu.Instance?.TextView === this && RichTextMenu.Instance.updateMenu(undefined, undefined, undefined, undefined);
FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = 'none');
}
@@ -1681,26 +1684,26 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
};
setFocus = (ipos?: number) => {
- const pos = ipos ?? (this._editorView?.state.selection.$from.pos || 1);
- setTimeout(() => this._editorView?.dispatch(this._editorView.state.tr.setSelection(TextSelection.near(this._editorView.state.doc.resolve(pos)))), 100);
+ const pos = ipos ?? (this.EditorView?.state.selection.$from.pos || 1);
+ setTimeout(() => this.EditorView?.dispatch(this.EditorView.state.tr.setSelection(TextSelection.near(this.EditorView.state.doc.resolve(pos)))), 100);
setTimeout(() => (this.ProseRef?.children?.[0] as HTMLElement).focus(), 200);
};
@action
onFocused = (e: React.FocusEvent): void => {
- // applyDevTools.applyDevTools(this._editorView);
+ // applyDevTools.applyDevTools(this.EditorView);
e.stopPropagation();
};
onClick = (e: React.MouseEvent): void => {
if (!this._props.isContentActive()) return;
- const editorView = this._editorView;
+ const editorView = this.EditorView;
const editorRoot = editorView?.root instanceof Document ? editorView.root : undefined;
if (editorView && (!this._forceUncollapse || editorRoot?.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 = editorView.posAtCoords({ left: e.clientX, top: e.clientY });
const node = pcords && editorView.state.doc.nodeAt(pcords.pos); // get what prosemirror thinks the clicked node is (if it's null, then we didn't click on any text)
if (pcords && node?.type === editorView.state.schema.nodes.dashComment) {
- this._editorView!.dispatch(editorView.state.tr.setSelection(TextSelection.create(editorView.state.doc, pcords.pos + 2)));
+ this.EditorView!.dispatch(editorView.state.tr.setSelection(TextSelection.create(editorView.state.doc, pcords.pos + 2)));
e.preventDefault();
}
if (!node && this.ProseRef) {
@@ -1726,33 +1729,33 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
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 });
+ const clickPos = this.EditorView!.posAtCoords({ left: x, top: y });
const clickPosVal = clickPos?.pos || 1;
let olistPos = clickPosVal;
if (clickPos && olistPos && this._props.rootSelected?.()) {
- const clickNode = this._editorView?.state.doc.resolve(olistPos).node();
- const nodeBef = this._editorView?.state.doc.resolve(Math.max(0, olistPos - 1)).node();
- olistPos = nodeBef?.type === this._editorView?.state.schema.nodes.ordered_list ? olistPos - 1 : olistPos;
- let $olistPos = this._editorView?.state.doc.resolve(olistPos);
- let olistNode = (nodeBef !== null || clickNode?.type === this._editorView?.state.schema.nodes.list_item) && olistPos === clickPos?.pos ? clickNode : nodeBef;
- if (olistNode?.type === this._editorView?.state.schema.nodes.list_item) {
+ const clickNode = this.EditorView?.state.doc.resolve(olistPos).node();
+ const nodeBef = this.EditorView?.state.doc.resolve(Math.max(0, olistPos - 1)).node();
+ olistPos = nodeBef?.type === this.EditorView?.state.schema.nodes.ordered_list ? olistPos - 1 : olistPos;
+ let $olistPos = this.EditorView?.state.doc.resolve(olistPos);
+ let olistNode = (nodeBef !== null || clickNode?.type === this.EditorView?.state.schema.nodes.list_item) && olistPos === clickPos?.pos ? clickNode : nodeBef;
+ if (olistNode?.type === this.EditorView?.state.schema.nodes.list_item) {
if ($olistPos && $olistPos.depth) {
olistNode = $olistPos.parent;
- $olistPos = this._editorView?.state.doc.resolve($olistPos.start($olistPos.depth - 1));
+ $olistPos = this.EditorView?.state.doc.resolve($olistPos.start($olistPos.depth - 1));
}
}
- const maxSize = this._editorView?.state.doc.content.size ?? 0;
- const listPos = this._editorView?.state.doc.resolve(Math.min(maxSize, clickPosVal === olistPos ? clickPosVal + 1 : clickPosVal));
+ const maxSize = this.EditorView?.state.doc.content.size ?? 0;
+ const listPos = this.EditorView?.state.doc.resolve(Math.min(maxSize, clickPosVal === olistPos ? clickPosVal + 1 : clickPosVal));
const listNode = listPos?.node();
- if (olistNode && olistNode.type === this._editorView?.state.schema.nodes.ordered_list && listNode) {
+ if (olistNode && olistNode.type === this.EditorView?.state.schema.nodes.ordered_list && listNode) {
if (!highlightOnly) {
if (selectOrderedList) {
- this._editorView.dispatch(this._editorView.state.tr.setSelection(new NodeSelection(selectOrderedList ? $olistPos! : listPos!)));
+ this.EditorView.dispatch(this.EditorView.state.tr.setSelection(new NodeSelection(selectOrderedList ? $olistPos! : listPos!)));
} else {
const nodePos = clickPosVal - (olistPos === clickPosVal ? 0 : 1);
- if (this._editorView.state.doc.nodeAt(nodePos)) {
- const tr = this._editorView.state.tr.setNodeMarkup(nodePos, listNode.type, { ...listNode.attrs, visibility: !listNode.attrs.visibility });
- this._editorView.dispatch(tr.setSelection(TextSelection.create(tr.doc, nodePos)));
+ if (this.EditorView.state.doc.nodeAt(nodePos)) {
+ const tr = this.EditorView.state.tr.setNodeMarkup(nodePos, listNode.type, { ...listNode.attrs, visibility: !listNode.attrs.visibility });
+ this.EditorView.dispatch(tr.setSelection(TextSelection.create(tr.doc, nodePos)));
}
}
}
@@ -1772,19 +1775,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
onBlur = (e: React.FocusEvent) => {
if (this.ProseRef?.children[0] !== e.nativeEvent.target) return;
if (!(this.EditorView?.state.selection instanceof NodeSelection) || this.EditorView.state.selection.node.type !== this.EditorView.state.schema.nodes.footnote) {
- const stordMarks = this._editorView?.state.storedMarks?.slice();
+ const stordMarks = this.EditorView?.state.storedMarks?.slice();
if (!(this.EditorView?.state.selection instanceof NodeSelection)) {
this.autoLink();
- if (this._editorView?.state.tr) {
+ if (this.EditorView?.state.tr) {
const tr = stordMarks?.reduce((tr2, m) => {
tr2.addStoredMark(m);
return tr2;
- }, this._editorView.state.tr);
- tr && this._editorView.dispatch(tr);
+ }, this.EditorView.state.tr);
+ tr && this.EditorView.dispatch(tr);
}
}
}
- if (RichTextMenu.Instance?.view === this._editorView && !(this._props.isContentActive() || this._props.rootSelected?.())) {
+ if (RichTextMenu.Instance?.view === this.EditorView && !(this._props.isContentActive() || this._props.rootSelected?.())) {
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, undefined);
}
@@ -1831,7 +1834,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
switch (e.key) {
case 'Escape':
- this._editorView!.dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from, state.selection.from)));
+ this.EditorView!.dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from, state.selection.from)));
(document.activeElement as HTMLElement).blur?.();
DocumentView.DeselectAll();
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, undefined);
@@ -1857,7 +1860,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
this.startUndoTypingBatch();
};
ondrop = (e: React.DragEvent) => {
- this._editorView!.dispatch(updateBullets(this._editorView!.state.tr, this._editorView!.state.schema));
+ this.EditorView?.dispatch(updateBullets(this.EditorView.state.tr, this.EditorView.state.schema));
e.stopPropagation(); // drag n drop of text within text note will generate a new note if not caughst, as will dragging in from outside of Dash.
};
onScroll = (e: React.UIEvent) => {
@@ -1872,7 +1875,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
tryUpdateScrollHeight = () => {
const margins = 2 * NumCast(this.layoutDoc._yMargin, this._props.yPadding || 0);
const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined;
- if (children && !SnappingManager.IsDragging) {
+ if (this.EditorView && children && !SnappingManager.IsDragging) {
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 => {
@@ -2093,7 +2096,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const paddingX = Math.max(NumCast(this.layoutDoc._xMargin), this._props.xPadding ?? 0, 0, ((this._props.screenXPadding?.() ?? 0) - scrMargin[0]) * this.ScreenToLocalBoxXf().Scale);
const paddingY = Math.max(NumCast(this.layoutDoc._yMargin), 0, ((this._props.yPadding ?? 0) - scrMargin[1]) * this.ScreenToLocalBoxXf().Scale);
const styleFromLayout = styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._header_height}px' >
- return styleFromLayout?.height === '0px' ? null : (
+ return this.isLabel ? (
+ <LabelBox {...this._props} />
+ ) : styleFromLayout?.height === '0px' ? null : (
<div
className="formattedTextBox"
ref={r => {
@@ -2116,6 +2121,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
fontSize: this.fontSize,
fontFamily: this.fontFamily,
fontWeight: this.fontWeight,
+ fontStyle: this.fontStyle,
+ textDecoration: this.fontDecoration,
...styleFromLayout,
}}>
<div
@@ -2156,8 +2163,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
paddingTop: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY}px`),
paddingBottom: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY}px`),
color: StrCast(this.layoutDoc.text_fontColor),
- fontWeight: `${this.layoutDoc.contentBold ? 'bold' : ''}`,
- textTransform: `${this.layoutDoc.textTransform}` as Property.TextTransform,
+ fontWeight: this.layoutDoc.contentBold ? 'bold' : '',
+ textTransform: StrCast(this.dataDoc[this.fieldKey + '_transform']) as Property.TextTransform,
}}
/>
</div>
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index 7a8b72be0..3c84e5a10 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -349,7 +349,9 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any): KeyMa
dispatch(tx4);
}
- if (view.state.selection.$anchor.nodeAfter?.type === schema.nodes.text && once) {
+ if (view.state.selection.$anchor.depth > 0 &&
+ view.state.selection.$anchor.node(view.state.selection.$anchor.depth-1).type === schema.nodes.list_item &&
+ view.state.selection.$anchor.nodeAfter?.type === schema.nodes.text && once) {
// if text is selected across list items, then we need to forcibly insert a new line since the splitBlock code joins the two list items.
enter(view.state, dispatch, view, false);
}
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 55e6a3a5b..62fbd23ea 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
-import { action, computed, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx';
+import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { lift, toggleMark, wrapIn } from 'prosemirror-commands';
import { Mark, MarkType } from 'prosemirror-model';
@@ -32,7 +32,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
public overMenu: boolean = false; // kind of hacky way to prevent selects not being selectable
private _linkToRef = React.createRef<HTMLInputElement>();
- layoutDoc: Doc | undefined;
+ dataDoc: Doc | undefined;
@observable public view?: EditorView & { TextView?: FormattedTextBox } = undefined;
public editorProps: FieldViewProps | AntimodeMenuProps | undefined;
@@ -41,7 +41,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
@observable private collapsed: boolean = false;
@observable private _noLinkActive: boolean = false;
@observable private _boldActive: boolean = false;
- @observable private _italicsActive: boolean = false;
+ @observable private _italicActive: boolean = false;
@observable private _underlineActive: boolean = false;
@observable private _strikethroughActive: boolean = false;
@observable private _subscriptActive: boolean = false;
@@ -49,6 +49,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
@observable private _activeFontSize: string = '13px';
@observable private _activeFontFamily: string = '';
+ @observable private _activeFitBox: boolean = false;
@observable private _activeListType: string = '';
@observable private _activeAlignment: string = 'left';
@@ -64,13 +65,12 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
@observable private currentLink: string | undefined = '';
@observable private showLinkDropdown: boolean = false;
- _reaction: IReactionDisposer | undefined;
constructor(props: AntimodeMenuProps) {
super(props);
makeObservable(this);
runInAction(() => {
RichTextMenu._instance.menu = this;
- this.updateMenu(undefined, undefined, props, this.layoutDoc);
+ this.updateMenu(undefined, undefined, props, this.dataDoc);
this._canFade = false;
this.Pinned = true;
});
@@ -89,8 +89,8 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
@computed get underline() {
return this._underlineActive;
}
- @computed get italics() {
- return this._italicsActive;
+ @computed get italic() {
+ return this._italicActive;
}
@computed get strikeThrough() {
return this._strikethroughActive;
@@ -101,6 +101,9 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
@computed get fontHighlight() {
return this._activeHighlightColor;
}
+ @computed get fitBox() {
+ return this._activeFitBox;
+ }
@computed get fontFamily() {
return this._activeFontFamily;
}
@@ -114,26 +117,16 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
return this._activeAlignment;
}
@computed get textVcenter() {
- return BoolCast(this.layoutDoc?._layout_centered);
- }
- _disposer: IReactionDisposer | undefined;
- componentDidMount() {
- // this._disposer = reaction(
- // () => DocumentView.Selected().slice(),
- // () => this.updateMenu(undefined, undefined, undefined, undefined)
- // );
- }
- componentWillUnmount() {
- this._disposer?.();
+ return BoolCast(this.dataDoc?._layout_centered, BoolCast(Doc.UserDoc().layout_centered));
}
@action
- public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: FormattedTextBoxProps | AntimodeMenuProps | undefined, layoutDoc: Doc | undefined) {
+ public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: FormattedTextBoxProps | AntimodeMenuProps | undefined, dataDoc: Doc | undefined) {
if (this._linkToRef.current?.getBoundingClientRect().width) {
return;
}
this.view = view;
- this.layoutDoc = layoutDoc;
+ this.dataDoc = dataDoc;
props && (this.editorProps = props);
// Don't do anything if the document/selection didn't change
@@ -147,12 +140,13 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
const { activeSizes } = active;
const { activeColors } = active;
const { activeHighlights } = active;
- const refDoc = DocumentView.Selected().lastElement()?.layoutDoc ?? Doc.UserDoc();
+ const refDoc = DocumentView.Selected().lastElement()?.dataDoc ?? Doc.UserDoc();
const refField = (pfx => (pfx ? pfx + '_' : ''))(DocumentView.Selected().lastElement()?.LayoutFieldKey);
const refVal = (field: string, dflt: string) => StrCast(refDoc[refField + field], StrCast(Doc.UserDoc()[field], dflt));
this._activeListType = this.getActiveListStyle();
this._activeAlignment = this.getActiveAlignment();
+ this._activeFitBox = BoolCast(refDoc[refField + 'fitBox'], BoolCast(Doc.UserDoc().fitBox));
this._activeFontFamily = !activeFamilies.length ? StrCast(this.TextView?.Document._text_fontFamily, refVal('fontFamily', 'Arial')) : activeFamilies.length === 1 ? String(activeFamilies[0]) : 'various';
this._activeFontSize = !activeSizes.length ? StrCast(this.TextView?.Document.fontSize, refVal('fontSize', '10px')) : activeSizes[0];
this._activeFontColor = !activeColors.length ? StrCast(this.TextView?.Document.fontColor, refVal('fontColor', 'black')) : activeColors.length > 0 ? String(activeColors[0]) : '...';
@@ -181,7 +175,6 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
toggleMark(mark.type, mark.attrs)(state, dispatch);
}
}
- // this.updateMenu(this.view, undefined, undefined, this.layoutDoc);
}
};
@@ -195,8 +188,10 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
return node.attrs.align || 'left';
}
}
+ } else if (this.dataDoc) {
+ return StrCast(this.dataDoc.text_align) || 'left';
}
- return 'left';
+ return StrCast(Doc.UserDoc().textAlign) || 'left';
};
// finds font sizes and families in selection
@@ -285,7 +280,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
this._noLinkActive = false;
this._boldActive = false;
- this._italicsActive = false;
+ this._italicActive = false;
this._underlineActive = false;
this._strikethroughActive = false;
this._subscriptActive = false;
@@ -295,7 +290,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
switch (mark.name) {
case 'noAutoLinkAnchor': this._noLinkActive = true; break;
case 'strong': this._boldActive = true; break;
- case 'em': this._italicsActive = true; break;
+ case 'em': this._italicActive = true; break;
case 'underline': this._underlineActive = true; break;
case 'strikethrough': this._strikethroughActive = true; break;
case 'subscript': this._subscriptActive = true; break;
@@ -330,6 +325,17 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
this.view.focus();
}
};
+ toggleFitBox = () => {
+ if (this.dataDoc) {
+ const doc = this.dataDoc;
+ (document.activeElement as HTMLElement)?.blur();
+ doc.text_fitBox = !doc.text_fitBox;
+ } else {
+ Doc.UserDoc().fitBox = !Doc.UserDoc().fitBox;
+ Doc.UserDoc().textAlign = Doc.UserDoc().fitBox ? 'center' : undefined;
+ }
+ this.updateMenu(undefined, undefined, undefined, this.dataDoc);
+ };
toggleBold = () => {
if (this.view) {
const mark = this.view.state.schema.mark(this.view.state.schema.marks.strong);
@@ -346,7 +352,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
};
- toggleItalics = () => {
+ toggleItalic = () => {
if (this.view) {
const mark = this.view.state.schema.mark(this.view.state.schema.marks.em);
this.setMark(mark, this.view.state, this.view.dispatch, false);
@@ -354,8 +360,8 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
};
- setFontField = (value: string, fontField: 'fontSize' | 'fontFamily' | 'fontColor' | 'fontHighlight') => {
- if (this.TextView && this.view) {
+ setFontField = (value: string, fontField: 'fitBox' | 'fontSize' | 'fontFamily' | 'fontColor' | 'fontHighlight') => {
+ if (this.TextView && this.view && fontField !== 'fitBox') {
const { text, paragraph } = this.view.state.schema.nodes;
const selNode = this.view.state.selection.$anchor.node();
if (this.view.state.selection.from === 1 && this.view.state.selection.empty && [undefined, text, paragraph].includes(selNode?.type)) {
@@ -367,9 +373,12 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
const fmark = this.view?.state.schema.marks['pF' + fontField.substring(1)].create(attrs);
this.setMark(fmark, this.view.state, (tx: Transaction) => this.view!.dispatch(tx.addStoredMark(fmark)), true);
this.view.focus();
+ } else if (this.dataDoc) {
+ this.dataDoc[`text_${fontField}`] = value;
+ this.updateMenu(undefined, undefined, undefined, this.dataDoc);
} else {
Doc.UserDoc()[fontField] = value;
- // this.updateMenu(this.view, undefined, this.props, this.layoutDoc);
+ this.updateMenu(undefined, undefined, undefined, this.dataDoc);
}
};
@@ -395,7 +404,6 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
this.view!.dispatch(tx3);
});
this.view.focus();
- // this.updateMenu(this.view, undefined, this.props, this.layoutDoc);
};
insertSummarizer(state: EditorState, dispatch: (tr: Transaction) => void) {
@@ -410,10 +418,11 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
vcenterToggle = () => {
- this.layoutDoc && (this.layoutDoc._layout_centered = !this.layoutDoc._layout_centered);
+ if (this.dataDoc) this.dataDoc._layout_centered = !this.dataDoc._layout_centered;
+ else Doc.UserDoc()._layout_centered = !Doc.UserDoc()._layout_centered;
};
- align = (view: EditorView, dispatch: (tr: Transaction) => void, alignment: 'left' | 'right' | 'center') => {
- if (this.RootSelected) {
+ align = (view: EditorView | undefined, dispatch: undefined | ((tr: Transaction) => void), alignment: 'left' | 'right' | 'center') => {
+ if (view && dispatch && this.RootSelected) {
let { tr } = view.state;
view.state.doc.nodesBetween(view.state.selection.from, view.state.selection.to, (node, pos) => {
if ([schema.nodes.paragraph, schema.nodes.heading].includes(node.type)) {
@@ -425,6 +434,11 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
});
view.focus();
dispatch?.(tr);
+ } else {
+ if (this.dataDoc) {
+ this.dataDoc.text_align = alignment;
+ } else Doc.UserDoc().textAlign = alignment;
+ this.updateMenu(undefined, undefined, undefined, this.dataDoc);
}
};
@@ -702,7 +716,7 @@ interface RichTextMenuPluginProps {
}
export class RichTextMenuPlugin extends React.Component<RichTextMenuPluginProps> {
update(view: EditorView & { TextView?: FormattedTextBox }, lastState: EditorState | undefined) {
- RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps, view.TextView?.layoutDoc);
+ RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps, view.TextView?.dataDoc);
}
render() {
return null;
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index f58434906..3d14ce4c0 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -121,7 +121,7 @@ export class RichTextRules {
annotationOn: textDoc,
_layout_fitWidth: true,
_layout_autoHeight: true,
- _text_fontSize: '9px',
+ text_fontSize: '9px',
title: 'inline comment',
});
textDocInline.title = inlineFieldKey; // give the annotation its own title
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 7448fa898..06869717a 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -14,7 +14,7 @@ import { StopEvent, lightOrDark, returnFalse, returnOne, setupMoveUpEvents } fro
import { emptyFunction, stringHash } from '../../../../Utils';
import { Doc, DocListCast, Field, FieldResult, FieldType, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
import { Animation, DocData, TransitionTimer } from '../../../../fields/DocSymbols';
-import { Copy } from '../../../../fields/FieldSymbols';
+import { Copy, Id } from '../../../../fields/FieldSymbols';
import { InkField } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
import { ObjectField } from '../../../../fields/ObjectField';
@@ -48,6 +48,7 @@ import './PresBox.scss';
import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums';
import SlideEffect from './SlideEffect';
import { AnimationSettings, SpringSettings, SpringType, easeItems, effectItems, effectTimings, movementItems, presEffectDefaultTimings, springMappings, springPreviewColors } from './SpringUtils';
+import _ from 'lodash';
@observer
export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -381,7 +382,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (typeof res === 'string') {
const resObj = JSON.parse(res);
console.log('Parsed GPT Result ', resObj);
- // eslint-disable-next-line no-restricted-syntax
for (const key in resObj) {
if (resObj[key]) {
console.log('typeof property', typeof resObj[key]);
@@ -562,11 +562,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const datarange = [DocumentType.FUNCPLOT].includes(targetType);
const dataview = [DocumentType.INK, DocumentType.COL, DocumentType.IMG, DocumentType.RTF].includes(targetType) && target?.activeFrame === undefined;
const poslayoutview = [DocumentType.COL].includes(targetType) && target?.activeFrame === undefined;
- const typeCollection = targetType === DocumentType.COL;
+ const collectionType = targetType === DocumentType.COL;
const filters = true;
const pivot = true;
const dataannos = false;
- return { scrollable, pannable, inkable, type_collection: typeCollection, pivot, map, filters, temporal, clippable, dataview, datarange, poslayoutview, dataannos };
+ return { scrollable, pannable, inkable, collectionType, pivot, map, filters, temporal, clippable, dataview, datarange, poslayoutview, dataannos };
}
@action
@@ -574,7 +574,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
/* empty */
};
@action
- // eslint-disable-next-line default-param-last
static restoreTargetDocView(bestTargetView: Opt<DocumentView>, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.config_pinLayout), pinDataTypes?: dataTypes, targetDoc?: Doc) {
const bestTarget = bestTargetView?.Document ?? (targetDoc?.layout_unrendered ? DocCast(targetDoc?.annotationOn) : targetDoc);
if (!bestTarget) return undefined;
@@ -700,15 +699,27 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
changed = true;
}
}
- if ((pinDataTypes?.type_collection && activeItem.config_viewType !== undefined) || (!pinDataTypes && activeItem.config_viewType !== undefined)) {
- if (bestTarget._type_collection !== activeItem.config_viewType) {
- bestTarget._type_collection = activeItem.config_viewType;
+ if ((pinDataTypes?.collectionType && activeItem.config_card_curDoc !== undefined) || (!pinDataTypes && activeItem.config_card_curDoc !== undefined)) {
+ if (bestTarget._card_curDoc !== activeItem.config_card_curDoc) {
+ bestTarget._card_curDoc = activeItem.config_card_curDoc;
+ changed = true;
+ }
+ }
+ if ((pinDataTypes?.collectionType && activeItem.config_carousel_index !== undefined) || (!pinDataTypes && activeItem.config_carousel_index !== undefined)) {
+ if (bestTarget._carousel_index !== activeItem.config_carousel_index) {
+ bestTarget._carousel_index = activeItem.config_carousel_index;
+ changed = true;
+ }
+ }
+ if ((pinDataTypes?.collectionType && activeItem.config_type_collection !== undefined) || (!pinDataTypes && activeItem.config_type_collection !== undefined)) {
+ if (bestTarget._type_collection !== activeItem.config_type_collection) {
+ bestTarget._type_collection = activeItem.config_type_collection;
changed = true;
}
}
if ((pinDataTypes?.filters && activeItem.config_docFilters !== undefined) || (!pinDataTypes && activeItem.config_docFilters !== undefined)) {
- if (bestTarget.childFilters !== activeItem.config_docFilters) {
+ if (!_.isEqual(Array.from(StrListCast(bestTarget.childFilters)), Array.from(StrListCast(activeItem.config_docFilters)))) {
bestTarget.childFilters = ObjectField.MakeCopy(activeItem.config_docFilters as ObjectField) || new List<string>([]);
changed = true;
}
@@ -1134,7 +1145,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return false;
}
} else if (doc.type !== DocumentType.PRES) {
- // eslint-disable-next-line operator-assignment
if (!doc.presentation_targetDoc) doc.title = doc.title + ' - Slide';
doc.presentation_targetDoc = doc.createdFrom ?? doc; // dropped document will be a new embedding of an embedded document somewhere else.
doc.presentation_movement = PresMovement.Zoom;
@@ -1166,8 +1176,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const tagDoc = Cast(curDoc.presentation_targetDoc, Doc, null);
if (curDoc && curDoc === this.activeItem)
return (
- // eslint-disable-next-line react/no-array-index-key
- <div key={index} className="selectedList-items">
+ <div key={doc[Id]} className="selectedList-items">
<b>
{index + 1}. {StrCast(curDoc.title)})
</b>
@@ -1175,15 +1184,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
);
if (tagDoc)
return (
- // eslint-disable-next-line react/no-array-index-key
- <div key={index} className="selectedList-items">
+ <div key={doc[Id]} className="selectedList-items">
{index + 1}. {StrCast(curDoc.title)}
</div>
);
if (curDoc)
return (
- // eslint-disable-next-line react/no-array-index-key
- <div key={index} className="selectedList-items">
+ <div key={doc[Id]} className="selectedList-items">
{index + 1}. {StrCast(curDoc.title)}
</div>
);
@@ -1368,7 +1375,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const tagDoc = PresBox.targetRenderedDoc(doc);
const srcContext = Cast(tagDoc.embedContainer, Doc, null);
const labelCreator = (top: number, left: number, edge: number, fontSize: number) => (
- // eslint-disable-next-line react/no-array-index-key
<div className="pathOrder" key={tagDoc.id + 'pres' + index} style={{ top, left, width: edge, height: edge, fontSize }} onClick={() => this.selectElement(doc)}>
<div className="pathOrder-frame">{index + 1}</div>
</div>
@@ -1619,7 +1625,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.updateEffect(this.activeItem.presentation_effect as PresEffect, false, true);
this.updateEffect(this.activeItem.presBulletEffect as PresEffect, true, true);
this.updateEffectDirection(this.activeItem.presentation_effectDirection as PresEffectDirection, true);
- // eslint-disable-next-line camelcase
const { presentation_transition: pt, presentation_duration: pd, presentation_hideBefore: ph, presentation_hideAfter: pa } = this.activeItem;
array.forEach(curDoc => {
curDoc.presentation_transition = pt;
@@ -2017,7 +2022,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="presBox-effects">
{this.generatedAnimations.map((elem, i) => (
<div
- // eslint-disable-next-line react/no-array-index-key
key={i}
className="presBox-effect-container"
onClick={() => {
@@ -2612,13 +2616,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
createTemplate = (layout: string, input?: string) => {
const x = this.activeItem && this.targetDoc ? NumCast(this.targetDoc.x) : 0;
const y = this.activeItem && this.targetDoc ? NumCast(this.targetDoc.y) + NumCast(this.targetDoc._height) + 20 : 0;
- const title = () => Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 58, _text_fontSize: '24pt' });
- const subtitle = () => Docs.Create.TextDocument('Click to change subtitle', { title: 'Slide subtitle', _width: 380, _height: 50, x: 10, y: 118, _text_fontSize: '16pt' });
- const header = () => Docs.Create.TextDocument('Click to change header', { title: 'Slide header', _width: 380, _height: 65, x: 10, y: 80, _text_fontSize: '20pt' });
- const contentTitle = () => Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 10, _text_fontSize: '24pt' });
- const content = () => Docs.Create.TextDocument('Click to change text', { title: 'Slide text', _width: 380, _height: 145, x: 10, y: 70, _text_fontSize: '14pt' });
- const content1 = () => Docs.Create.TextDocument('Click to change text', { title: 'Column 1', _width: 185, _height: 140, x: 10, y: 80, _text_fontSize: '14pt' });
- const content2 = () => Docs.Create.TextDocument('Click to change text', { title: 'Column 2', _width: 185, _height: 140, x: 205, y: 80, _text_fontSize: '14pt' });
+ const title = () => Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 58, text_fontSize: '24pt' });
+ const subtitle = () => Docs.Create.TextDocument('Click to change subtitle', { title: 'Slide subtitle', _width: 380, _height: 50, x: 10, y: 118, text_fontSize: '16pt' });
+ const header = () => Docs.Create.TextDocument('Click to change header', { title: 'Slide header', _width: 380, _height: 65, x: 10, y: 80, text_fontSize: '20pt' });
+ const contentTitle = () => Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 10, text_fontSize: '24pt' });
+ const content = () => Docs.Create.TextDocument('Click to change text', { title: 'Slide text', _width: 380, _height: 145, x: 10, y: 70, text_fontSize: '14pt' });
+ const content1 = () => Docs.Create.TextDocument('Click to change text', { title: 'Column 1', _width: 185, _height: 140, x: 10, y: 80, text_fontSize: '14pt' });
+ const content2 = () => Docs.Create.TextDocument('Click to change text', { title: 'Column 2', _width: 185, _height: 140, x: 205, y: 80, text_fontSize: '14pt' });
// prettier-ignore
switch (layout) {
case 'blank': return Docs.Create.FreeformDocument([], { title: input || 'Blank slide', _width: 400, _height: 225, x, y });
@@ -3045,7 +3049,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="Slide">
{mode !== CollectionViewType.Invalid ? (
<CollectionView
- // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
PanelWidth={this._props.PanelWidth}
PanelHeight={this.panelHeight}
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index d5f5f620c..a7e78bcea 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -572,18 +572,19 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
<div style={{ height: '80%' }}>
{this.heading(this.mode === GPTPopupMode.SORT ? 'SORTING' : 'QUIZ')}
<>
- {!this.cardsDoneLoading ? (
- <div className="content-wrapper">
- <div className="loading-spinner">
- <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
- {this.loading ? <span>Loading...</span> : <span>Reading Cards...</span>}
+ {
+ !this.cardsDoneLoading ? (
+ <div className="content-wrapper">
+ <div className="loading-spinner">
+ <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
+ {this.loading ? <span>Loading...</span> : <span>Reading Cards...</span>}
+ </div>
</div>
- </div>
- ) : this.mode === GPTPopupMode.CARD ? (
- this.cardMenu()
- ) : (
- this.cardActual(this.mode)
- ) // Call the functions to render JSX
+ ) : this.mode === GPTPopupMode.CARD ? (
+ this.cardMenu()
+ ) : (
+ this.cardActual(this.mode)
+ ) // Call the functions to render JSX
}
</>
</div>
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 358557ad7..920c9ea8b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -377,7 +377,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
if ((e.button !== 0 || e.altKey) && this._props.isContentActive()) {
this._setPreviewCursor?.(e.clientX, e.clientY, true, false, this._props.Document);
}
- if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this._props.isContentActive() && Doc.ActiveTool !== InkTool.Ink) {
this._props.select(false);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this.isAnnotating = true;
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
index b4635673c..d0f6566a5 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ b/src/client/views/smartdraw/SmartDrawHandler.tsx
@@ -21,7 +21,7 @@ import { SVGToBezier, SVGType } from '../../util/bezierFit';
import { InkingStroke } from '../InkingStroke';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { MarqueeView } from '../collections/collectionFreeForm';
-import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, DocumentView } from '../nodes/DocumentView';
+import { ActiveInkArrowEnd, ActiveInkArrowStart, ActiveInkDash, ActiveInkFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, DocumentView } from '../nodes/DocumentView';
import './SmartDrawHandler.scss';
export interface DrawingOptions {
@@ -105,14 +105,14 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
y: bounds.top - inkWidth / 2,
_width: bounds.width + inkWidth,
_height: bounds.height + inkWidth,
- stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
+ stroke_showLabel: !BoolCast(Doc.UserDoc().activeHideTextLabels)}, // prettier-ignore
inkWidth,
opts.autoColor ? stroke[1] : ActiveInkColor(),
ActiveInkBezierApprox(),
- stroke[2] === 'none' ? ActiveFillColor() : stroke[2],
- ActiveArrowStart(),
- ActiveArrowEnd(),
- ActiveDash(),
+ stroke[2] === 'none' ? ActiveInkFillColor() : stroke[2],
+ ActiveInkArrowStart(),
+ ActiveInkArrowEnd(),
+ ActiveInkDash(),
ActiveIsInkMask()
);
drawing.push(inkDoc);