From a4e3b645317c4589cf49f8007f6e6b57cf2c12d3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 4 Nov 2023 23:29:56 -0400 Subject: cleanup --- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index f9afe4d53..085f9f023 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -6,7 +6,7 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField } from '../../../fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { numberRange, OmitKeys } from '../../../Utils'; +import { numberRange } from '../../../Utils'; import { DocumentManager } from '../../util/DocumentManager'; import { SelectionManager } from '../../util/SelectionManager'; import { Transform } from '../../util/Transform'; -- cgit v1.2.3-70-g09d2 From d460d2ec856c9fc13789e151c9738f3345e95b64 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 10 Nov 2023 14:03:06 -0500 Subject: cleanup. fix color setting/interpolation for freeform animated views. --- .../CollectionFreeFormLayoutEngines.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 11 +-- src/client/views/global/globalScripts.ts | 6 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 78 ++++++---------------- 4 files changed, 30 insertions(+), 71 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index f9f9b5637..4484f664f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -28,6 +28,8 @@ export interface ViewDefBounds { } export interface PoolData { + pair: { layout: Doc; data?: Doc }; + replica: string; x: number; y: number; z?: number; @@ -40,9 +42,7 @@ export interface PoolData { opacity?: number; transition?: string; highlight?: boolean; - replica: string; - pointerEvents?: string; // without this, toggling lockPosition of a group/collection in a freeform view won't update until something else invalidates the freeform view's documents forcing -- this is a problem with doLayoutComputation which makes a performance test to insure somethingChanged - pair: { layout: Doc; data?: Doc }; + pointerEvents?: string; } export interface ViewDefResult { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ce1aa87af..27c3eaa93 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -35,6 +35,7 @@ import { COLLECTION_BORDER_WIDTH } from '../../../views/global/globalCssVariable import { Timeline } from '../../animationtimeline/Timeline'; import { ContextMenu } from '../../ContextMenu'; import { GestureOverlay } from '../../GestureOverlay'; +import { CtrlKey } from '../../GlobalKeyHandler'; import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke'; import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView'; @@ -52,7 +53,6 @@ import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCurso import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; import React = require('react'); -import { CtrlKey } from '../../GlobalKeyHandler'; export type collectionFreeformViewProps = { NativeWidth?: () => number; @@ -1422,7 +1422,7 @@ export class CollectionFreeFormView extends CollectionSubView this._cachedPool.set(k[0], k[1])); const elements = computedElementData.slice(); diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index b529991cb..8c49dc6ea 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -1,6 +1,6 @@ import { Colors } from 'browndash-components'; import { action, runInAction } from 'mobx'; -import { Doc } from '../../../fields/Doc'; +import { Doc, Opt } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; @@ -52,7 +52,9 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b const layoutFrameNumber = Cast(dv.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values const contentFrameNumber = Cast(dv.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed if (contentFrameNumber !== undefined) { - CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.rootDoc, { fieldKey: color }); + const obj: { [key: string]: Opt } = {}; + obj[fieldKey as any] = color; + CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.rootDoc, obj); } else { dv.rootDoc['_' + fieldKey] = color; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 085f9f023..09dfa4f99 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -18,8 +18,8 @@ import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; import React = require('react'); export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { - dataProvider?: (doc: Doc, replica: string) => { x: number; y: number; zIndex?: number; rotation?: number; color?: string; backgroundColor?: string; opacity?: number; highlight?: boolean; z: number; transition?: string } | undefined; - sizeProvider?: (doc: Doc, replica: string) => { width: number; height: number } | undefined; + dataProvider: (doc: Doc, replica: string) => { x: number; y: number; zIndex?: number; rotation?: number; color?: string; backgroundColor?: string; opacity?: number; highlight?: boolean; z: number; transition?: string }; + sizeProvider: (doc: Doc, replica: string) => { width: number; height: number }; renderCutoffProvider: (doc: Doc) => boolean; zIndex?: number; dataTransition?: string; @@ -29,14 +29,17 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { @observer export class CollectionFreeFormDocumentView extends DocComponent() { + get displayName() { // this makes mobx trace() statements more descriptive + return 'CollectionFreeFormDocumentView(' + this.rootDoc.title + ')'; + } // prettier-ignore public static animFields: { key: string; val?: number }[] = [ - { key: '_height' }, - { key: '_width' }, { key: 'x' }, { key: 'y' }, + { key: 'opacity', val: 1 }, + { key: '_height' }, + { key: '_width' }, { key: '_rotation', val: 0 }, { key: '_layout_scrollTop' }, - { key: 'opacity', val: 1 }, { key: '_currentFrame' }, { key: 'freeform_scale', val: 1 }, { key: 'freeform_panX' }, @@ -44,52 +47,28 @@ export class CollectionFreeFormDocumentView extends DocComponent (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames + + get X() { return this.dataProvider.x; } // prettier-ignore + get Y() { return this.dataProvider.y; } // prettier-ignore + get ZInd() { return this.dataProvider.zIndex ?? NumCast(this.Document.zIndex); } // prettier-ignore + get Rot() { return this.dataProvider.rotation ?? NumCast(this.Document._rotation); } // prettier-ignore + get Opacity() { return this.dataProvider.opacity; } // prettier-ignore + get BackgroundColor() { return this.dataProvider.backgroundColor ?? Cast(this.Document._backgroundColor, 'string', null); } // prettier-ignore + get Color() { return this.dataProvider.color ?? Cast(this.Document._color, 'string', null); } // prettier-ignore + @observable _animPos: number[] | undefined = undefined; @observable _contentView: DocumentView | undefined | null; - get displayName() { - // this makes mobx trace() statements more descriptive - return 'CollectionFreeFormDocumentView(' + this.rootDoc.title + ')'; - } - get transform() { - return `translate(${this.X}px, ${this.Y}px) rotate(${NumCast(this.Rot, this.Rot)}deg)`; - } - get X() { - return this.dataProvider?.x ?? NumCast(this.Document.x); - } - get Y() { - return this.dataProvider?.y ?? NumCast(this.Document.y); - } - get ZInd() { - return this.dataProvider?.zIndex ?? NumCast(this.Document.zIndex); - } - get Rot() { - return this.dataProvider?.rotation ?? NumCast(this.Document._rotation); - } - get Opacity() { - return this.dataProvider?.opacity; - } - get BackgroundColor() { - return this.dataProvider?.backgroundColor ?? Cast(this.Document._backgroundColor, 'string', null); - } - get Color() { - return this.dataProvider?.color ?? Cast(this.Document._color, 'string', null); - } - @computed get dataProvider() { - return this.props.dataProvider?.(this.props.Document, this.props.replica); - } - @computed get sizeProvider() { - return this.props.sizeProvider?.(this.props.Document, this.props.replica); - } + @computed get dataProvider() { return this.props.dataProvider(this.props.Document, this.props.replica); } // prettier-ignore + @computed get sizeProvider() { return this.props.sizeProvider(this.props.Document, this.props.replica); } // prettier-ignore styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (doc === this.layoutDoc) { - // prettier-ignore switch (property) { case StyleProp.Opacity: return this.Opacity; // only change the opacity for this specific document, not its children case StyleProp.BackgroundColor: return this.BackgroundColor; case StyleProp.Color: return this.Color; - } + } // prettier-ignore } return this.props.styleProvider?.(doc, props, property); }; @@ -126,21 +105,6 @@ export class CollectionFreeFormDocumentView extends DocComponent(); - const height = new List(); - const top = new List(); - const left = new List(); - width.push(NumCast(targDoc._width)); - height.push(NumCast(targDoc._height)); - top.push(NumCast(targDoc._height) / -2); - left.push(NumCast(targDoc._width) / -2); - doc['viewfinder-width-indexed'] = width; - doc['viewfinder-height-indexed'] = height; - doc['viewfinder-top-indexed'] = top; - doc['viewfinder-left-indexed'] = left; - } - public static setupKeyframes(docs: Doc[], currTimecode: number, makeAppear: boolean = false) { docs.forEach(doc => { if (doc.appearFrame === undefined) doc.appearFrame = currTimecode; @@ -221,7 +185,7 @@ export class CollectionFreeFormDocumentView extends DocComponent Date: Thu, 16 Nov 2023 14:57:29 -0500 Subject: fixed alt-drag to toggle scroll mode. fixed replaceTab to work properly with panelNames. made slides pointing to trails open the target trails in situ. cleaned up code when starting drag to call freeformview more nicel. fixed brush/highlight of tabs. made collectionFreeformView/FreeformDocs use a more robust and simpler approach to caching freeform values. --- src/client/util/DragManager.ts | 6 +- src/client/views/DocumentDecorations.tsx | 9 +- src/client/views/GlobalKeyHandler.ts | 111 ++++++-------- src/client/views/InkStrokeProperties.ts | 4 +- src/client/views/InkingStroke.tsx | 2 +- src/client/views/MainView.tsx | 19 ++- .../views/collections/CollectionDockingView.tsx | 7 +- src/client/views/collections/CollectionMenu.tsx | 2 +- .../views/collections/CollectionNoteTakingView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 2 +- src/client/views/collections/TabDocView.scss | 1 - src/client/views/collections/TabDocView.tsx | 82 +++++----- .../collectionFreeForm/CollectionFreeFormView.tsx | 128 +++++----------- .../collections/collectionFreeForm/MarqueeView.tsx | 10 +- src/client/views/global/globalScripts.ts | 2 +- .../nodes/CollectionFreeFormDocumentView.scss | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 170 ++++++++++++++------- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 39 +++-- src/client/views/nodes/KeyValuePair.tsx | 4 +- src/client/views/nodes/LinkBox.tsx | 4 +- src/client/views/nodes/trails/PresBox.tsx | 11 +- 22 files changed, 313 insertions(+), 308 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 8d8975763..e59e847c2 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -198,7 +198,7 @@ export namespace DragManager { }; const finishDrag = async (e: DragCompleteEvent) => { const docDragData = e.docDragData; - setTimeout(() => dragData.draggedViews.forEach(view => view.props.CollectionFreeFormDocumentView?.().dragEnding())); + setTimeout(() => dragData.draggedViews.forEach(view => view.props.dragEnding?.())); onDropCompleted?.(e); // glr: optional additional function to be called - in this case with presentation trails if (docDragData && !docDragData.droppedDocuments.length) { docDragData.dropAction = dragData.userDropAction || dragData.dropAction; @@ -234,7 +234,7 @@ export namespace DragManager { }; dragData.draggedDocuments.map(d => d.dragFactory); // does this help? trying to make sure the dragFactory Doc is loaded StartDrag(eles, dragData, downX, downY, options, finishDrag); - dragData.draggedViews.forEach(view => view.props.CollectionFreeFormDocumentView?.().dragStarting()); + dragData.draggedViews.forEach(view => view.props.dragStarting?.()); return true; } @@ -475,7 +475,7 @@ export namespace DragManager { }; const cleanupDrag = action((undo: boolean) => { - (dragData as DocumentDragData).draggedViews?.forEach(view => view.props.CollectionFreeFormDocumentView?.().dragEnding()); + (dragData as DocumentDragData).draggedViews?.forEach(view => view.props.dragEnding?.()); hideDragShowOriginalElements(false); document.removeEventListener('pointermove', moveHandler, true); document.removeEventListener('pointerup', upHandler, true); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ff7daa2eb..33886e791 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -486,8 +486,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P this._snapY = e.pageY; const ffviewSet = new Set(); SelectionManager.Views().forEach(docView => { - const ffview = docView.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; - ffview && ffviewSet.add(ffview); + docView.CollectionFreeFormView && ffviewSet.add(docView.CollectionFreeFormView); this._dragHeights.set(docView.layoutDoc, { start: NumCast(docView.rootDoc._height), lowest: NumCast(docView.rootDoc._height) }); }); Array.from(ffviewSet).map(ffview => ffview.dragStarting(false, false)); @@ -814,8 +813,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P bounds.r = Math.max(bounds.x, Math.max(leftBounds, Math.min(window.innerWidth, bounds.r + borderRadiusDraggerWidth + this._resizeBorderWidth / 2) - this._resizeBorderWidth / 2 - borderRadiusDraggerWidth)); bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight)); - const useLock = bounds.r - bounds.x > 135 && seldocview.props.CollectionFreeFormDocumentView; - const useRotation = !hideResizers && seldocview.rootDoc.type !== DocumentType.EQUATION && seldocview.props.CollectionFreeFormDocumentView; // when do we want an object to not rotate? + const useLock = bounds.r - bounds.x > 135 && seldocview.CollectionFreeFormDocumentView; + const useRotation = !hideResizers && seldocview.rootDoc.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate? const rotation = SelectionManager.Views().length == 1 ? NumCast(seldocview.rootDoc._rotation) : 0; const resizerScheme = ''; @@ -878,7 +877,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P )} ); - const freeformDoc = SelectionManager.Views().some(v => v.props.CollectionFreeFormDocumentView?.()); + const freeformDoc = SelectionManager.Views().some(v => v.CollectionFreeFormDocumentView); return (
{ + const nudgeable = SelectionManager.Views().some(dv => dv.CollectionFreeFormDocumentView?.nudge); + nudgeable && UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.CollectionFreeFormDocumentView?.nudge(x, y)), label); + return { stopPropagation: nudgeable, preventDefault: nudgeable }; + }; + private unmodified = action((keyname: string, e: KeyboardEvent) => { - const hasFffView = SelectionManager.Views().some(dv => dv.props.CollectionFreeFormDocumentView?.()); switch (keyname) { case 'u': - if (document.activeElement?.tagName === 'INPUT' || document.activeElement?.tagName === 'TEXTAREA') { - return { stopPropagation: false, preventDefault: false }; + if (document.activeElement?.tagName !== 'INPUT' && document.activeElement?.tagName !== 'TEXTAREA') { + const ungroupings = SelectionManager.Views().slice(); + UndoManager.RunInBatch(() => ungroupings.map(dv => (dv.layoutDoc.group = undefined)), 'ungroup'); + SelectionManager.DeselectAll(); } - - const ungroupings = SelectionManager.Views().slice(); - UndoManager.RunInBatch(() => ungroupings.map(dv => (dv.layoutDoc.group = undefined)), 'ungroup'); - SelectionManager.DeselectAll(); break; case 'g': - if (document.activeElement?.tagName === 'INPUT' || document.activeElement?.tagName === 'TEXTAREA') { - return { stopPropagation: false, preventDefault: false }; - } - - const groupings = SelectionManager.Views().slice(); - const randomGroup = random(0, 1000); - const collectionView = groupings.reduce( - (col, g) => (col === null || g.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView === col ? g.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView : undefined), - null as null | undefined | CollectionFreeFormView - ); - if (collectionView) { - UndoManager.RunInBatch(() => { - collectionView._marqueeViewRef.current?.collection( - e, - true, - groupings.map(g => g.rootDoc) - ); - }, 'grouping'); - break; + if (document.activeElement?.tagName !== 'INPUT' && document.activeElement?.tagName !== 'TEXTAREA') { + const groupings = SelectionManager.Views().slice(); + const randomGroup = random(0, 1000); + const collectionView = groupings.reduce((col, g) => (col === null || g.CollectionFreeFormView === col ? g.CollectionFreeFormView : undefined), null as null | undefined | CollectionFreeFormView); + if (collectionView) { + UndoManager.RunInBatch(() => { + collectionView._marqueeViewRef.current?.collection( + e, + true, + groupings.map(g => g.rootDoc) + ); + }, 'grouping'); + break; + } + UndoManager.RunInBatch(() => groupings.map(dv => (dv.layoutDoc.group = randomGroup)), 'group'); + SelectionManager.DeselectAll(); } - UndoManager.RunInBatch(() => groupings.map(dv => (dv.layoutDoc.group = randomGroup)), 'group'); - SelectionManager.DeselectAll(); break; case ' ': // MarqueeView.DragMarquee = !MarqueeView.DragMarquee; // bcz: this needs a better disclosure UI @@ -167,19 +165,11 @@ export class KeyManager { return { stopPropagation: true, preventDefault: true }; } break; - case 'arrowleft': - UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.props.CollectionFreeFormDocumentView?.().nudge(-1, 0)), 'nudge left'); - return { stopPropagation: hasFffView, preventDefault: hasFffView }; - case 'arrowright': - UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.props.CollectionFreeFormDocumentView?.().nudge?.(1, 0)), 'nudge right'); - return { stopPropagation: hasFffView, preventDefault: hasFffView }; - case 'arrowup': - UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.props.CollectionFreeFormDocumentView?.().nudge?.(0, -1)), 'nudge up'); - return { stopPropagation: hasFffView, preventDefault: hasFffView }; - case 'arrowdown': - UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.props.CollectionFreeFormDocumentView?.().nudge?.(0, 1)), 'nudge down'); - return { stopPropagation: hasFffView, preventDefault: hasFffView }; - } + case 'arrowleft': return this.nudge(-1,0, 'nudge left') + case 'arrowright': return this.nudge(1,0, 'nudge right'); + case 'arrowup': return this.nudge(0, -1, 'nudge up'); + case 'arrowdown': return this.nudge(0, 1, 'nudge down'); + } // prettier-ignore return { stopPropagation: false, @@ -188,37 +178,24 @@ export class KeyManager { }); private shift = action((keyname: string) => { - const stopPropagation = false; - const preventDefault = false; - switch (keyname) { - case 'arrowleft': - UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.props.CollectionFreeFormDocumentView?.().nudge?.(-10, 0)), 'nudge left'); - break; - case 'arrowright': - UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.props.CollectionFreeFormDocumentView?.().nudge?.(10, 0)), 'nudge right'); - break; - case 'arrowup': - UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.props.CollectionFreeFormDocumentView?.().nudge?.(0, -10)), 'nudge up'); - break; - case 'arrowdown': - UndoManager.RunInBatch(() => SelectionManager.Views().map(dv => dv.props.CollectionFreeFormDocumentView?.().nudge?.(0, 10)), 'nudge down'); - break; + case 'arrowleft': return this.nudge(-10,0, 'nudge left'); + case 'arrowright': return this.nudge(10, 0, 'nudge right'); + case 'arrowup': return this.nudge(0, -10, 'nudge up'); + case 'arrowdown': return this.nudge(0, 10, 'nudge down'); case 'g': - if (document.activeElement?.tagName === 'INPUT' || document.activeElement?.tagName === 'TEXTAREA') { - return { stopPropagation: false, preventDefault: false }; + if (document.activeElement?.tagName !== 'INPUT' && document.activeElement?.tagName !== 'TEXTAREA') { + const groupings = SelectionManager.Views().slice(); + const randomGroup = random(0, 1000); + UndoManager.RunInBatch(() => groupings.map(dv => (dv.layoutDoc.group = randomGroup)), 'group'); + SelectionManager.DeselectAll(); } - - const groupings = SelectionManager.Views().slice(); - const randomGroup = random(0, 1000); - UndoManager.RunInBatch(() => groupings.map(dv => (dv.layoutDoc.group = randomGroup)), 'group'); - SelectionManager.DeselectAll(); break; - } + } // prettier-ignore return { - stopPropagation: stopPropagation, - preventDefault: preventDefault, + stopPropagation: false, + preventDefault: false, }; }); @@ -230,7 +207,7 @@ export class KeyManager { case 'ƒ': case 'f': const dv = SelectionManager.Views()?.[0]; - UndoManager.RunInBatch(() => dv.props.CollectionFreeFormDocumentView?.().float(), 'float'); + UndoManager.RunInBatch(() => dv.CollectionFreeFormDocumentView?.float(), 'float'); } return { diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 736ca8d90..62165bc48 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -372,8 +372,8 @@ export class InkStrokeProperties { }; snapToAllCurves = (screenDragPt: { X: number; Y: number }, inkView: DocumentView, snapData: { nearestPt: { X: number; Y: number }; distance: number }, ink: InkData, controlIndex: number) => { - const containingCollection = inkView.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; - const containingDocView = inkView.props.CollectionFreeFormDocumentView?.().props.DocumentView?.(); + const containingCollection = inkView.CollectionFreeFormView; + const containingDocView = containingCollection?.props.DocumentView?.(); containingCollection?.childDocs .filter(doc => doc.type === DocumentType.INK) .forEach(doc => { diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 513061e79..cf565abc8 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -466,7 +466,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { { if (pres.type === DocumentType.PRES) { - CollectionDockingView.AddSplit(pres, OpenWhereMod.right); + CollectionDockingView.AddSplit(pres, OpenWhereMod.right, undefined, PresBox.PanelName); Doc.MyTrails && (Doc.ActivePresentation = pres); Doc.AddDocToList(Doc.MyTrails, 'data', pres); this.closeFlyout(); @@ -696,16 +698,17 @@ export class MainView extends React.Component { mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftScreenOffsetOfMainDocView, 0); static addDocTabFunc_impl = (doc: Doc, location: OpenWhere): boolean => { const whereFields = location.split(':'); - const keyValue = whereFields[1]?.includes('KeyValue'); - const whereMods: OpenWhereMod = whereFields.length > 1 ? (whereFields[1].replace('KeyValue', '') as OpenWhereMod) : OpenWhereMod.none; + const keyValue = whereFields.includes(OpenWhereMod.keyvalue); + const whereMods = whereFields.length > 1 ? (whereFields[1] as OpenWhereMod) : OpenWhereMod.none; + const panelName = whereFields.length > 1 ? whereFields.lastElement() : ''; if (doc.dockingConfig && !keyValue) return DashboardView.openDashboard(doc); - // prettier-ignore switch (whereFields[0]) { case OpenWhere.lightbox: return LightboxView.Instance.AddDocTab(doc, location); case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods); - case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods, undefined, "dontSelectOnActivate"); // bcz: hack! mark the toggle so that it won't be selected on activation- this is needed so that the backlinks menu can toggle views of targets on and off without selecting them + case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods, undefined, TabDocView.DontSelectOnActivate); // bcz: hack! mark the toggle so that it won't be selected on activation- this is needed so that the backlinks menu can toggle views of targets on and off without selecting them + case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, whereMods, undefined, panelName); case OpenWhere.add:default:return CollectionDockingView.AddSplit(doc, whereMods, undefined, undefined, keyValue); - } + } // prettier-ignore }; @computed get flyout() { @@ -923,7 +926,7 @@ export class MainView extends React.Component { SnappingManager.GetIsDragging(); SnappingManager.GetIsResizing(); const dragged = DragManager.docsBeingDragged.lastElement() ?? SelectionManager.Docs().lastElement(); - const dragPar = dragged ? DocumentManager.Instance.getDocumentView(dragged)?.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView : undefined; + const dragPar = dragged ? DocumentManager.Instance.getDocumentView(dragged)?.CollectionFreeFormView : undefined; return !dragPar?.rootDoc.freeform_snapLines ? null : (
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 1b616d6a8..9c644e2cc 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -130,7 +130,7 @@ export class CollectionDockingView extends CollectionSubView() { @undoBatch @action - public static ReplaceTab(document: Doc, panelName: OpenWhereMod, stack: any, addToSplit?: boolean, keyValue?: boolean): boolean { + public static ReplaceTab(document: Doc, mods: OpenWhereMod, stack: any, panelName: string, addToSplit?: boolean, keyValue?: boolean): boolean { const instance = CollectionDockingView.Instance; if (!instance) return false; const newConfig = CollectionDockingView.makeDocumentConfig(document, panelName, undefined, keyValue); @@ -151,7 +151,7 @@ export class CollectionDockingView extends CollectionSubView() { } return false; } - return CollectionDockingView.AddSplit(document, panelName, stack, panelName); + return CollectionDockingView.AddSplit(document, mods, stack, panelName); } @undoBatch @@ -619,6 +619,3 @@ ScriptingGlobals.add( 'opens up document in screen overlay layer', '(doc: any)' ); -ScriptingGlobals.add(function useRightSplit(doc: any, addToRightSplit?: boolean) { - CollectionDockingView.ReplaceTab(doc, OpenWhereMod.right, undefined, addToRightSplit); -}); diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 22f0f8a1f..cf154be8d 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -652,7 +652,7 @@ export class CollectionViewBaseChrome extends React.Component this.props.docView.props.CollectionFreeFormDocumentView?.().float())}> + onClick={undoBatch(() => this.props.docView.CollectionFreeFormDocumentView?.float())}> diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index ac72a45e0..ac916fef3 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -443,7 +443,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } return true; } - } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) { + } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' }); if (!this.props.addDocument?.(source)) e.preventDefault(); de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index e5695f63b..da00093dd 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -471,7 +471,7 @@ export class CollectionStackingView extends CollectionSubView { @computed get layoutDoc() { return this._document && Doc.Layout(this._document); } - @computed get tabBorderColor() { - const highlight = DefaultStyleProvider(this._document, undefined, StyleProp.Highlighting); - if (highlight?.highlightIndex === Doc.DocBrushStatus.highlighted) return highlight.highlightColor; - return 'transparent'; - } - @computed get tabColor() { - return this._isUserActivated ? Colors.WHITE : this._hovering ? Colors.LIGHT_GRAY : Colors.MEDIUM_GRAY; - } - @computed get tabTextColor() { - return this._document?.type === DocumentType.PRES ? 'black' : StrCast(this._document?._color, StrCast(this._document?.color, DefaultStyleProvider(this._document, undefined, StyleProp.Color))); - } - // @computed get renderBounds() { - // const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0]; - // const xbounds = bounds[2] - bounds[0]; - // const ybounds = bounds[3] - bounds[1]; - // const dim = Math.max(xbounds, ybounds); - // return { l: bounds[0] + xbounds / 2 - dim / 2, t: bounds[1] + ybounds / 2 - dim / 2, cx: bounds[0] + xbounds / 2, cy: bounds[1] + ybounds / 2, dim }; - // } get stack() { return (this.props as any).glContainer.parent.parent; @@ -163,14 +145,31 @@ export class TabDocView extends React.Component { tab.reactComponents = [iconWrap, closeWrap]; tab.element[0].prepend(iconWrap); tab._disposers.color = reaction( - () => ({ color: this.tabColor, borderColor: this.tabBorderColor }), - coloring => { - const textColor = lightOrDark(this.tabColor); //not working with StyleProp.Color + () => ({ variant: SettingsManager.userVariantColor, degree: Doc.GetBrushStatus(doc), highlight: DefaultStyleProvider(this._document, undefined, StyleProp.Highlighting) }), + ({ variant, degree, highlight }) => { + const color = highlight?.highlightIndex === Doc.DocBrushStatus.highlighted ? highlight.highlightColor : degree ? ['transparent', variant, variant, 'orange'][degree] : variant; + + const textColor = color === variant ? SettingsManager.userColor : lightOrDark(color); titleEle.style.color = textColor; - titleEle.style.backgroundColor = coloring.borderColor; iconWrap.style.color = textColor; closeWrap.style.color = textColor; - tab.element[0].style.background = coloring.color; + tab.element[0].style.background = + color === variant + ? DashColor(color) + .fade( + this._isUserActivated + ? 0 + : this._hovering + ? 0.25 + : degree === Doc.DocBrushStatus.selfBrushed + ? 0.5 + : degree === Doc.DocBrushStatus.protoBrushed // + ? 0.7 + : 0.9 + ) + .rgb() + .toString() + : color; }, { fireImmediately: true } ); @@ -181,6 +180,10 @@ export class TabDocView extends React.Component { tab.header.parent.setActiveContentItem(tab.contentItem); tab.setActive(true); } + this._document && Doc.BrushDoc(this._document); + }; + tab.element[0].onmouseleave = (e: MouseEvent) => { + this._document && Doc.UnBrushDoc(this._document); }; tab.element[0].oncontextmenu = (e: MouseEvent) => { @@ -210,22 +213,18 @@ export class TabDocView extends React.Component { if (selected && tab.contentItem !== tab.header.parent.getActiveContentItem()) { undoable(() => tab.header.parent.setActiveContentItem(tab.contentItem), 'tab switch')(); } - toggle.style.fontWeight = selected ? 'bold' : ''; + //toggle.style.fontWeight = selected ? 'bold' : ''; // toggle.style.textTransform = selected ? "uppercase" : ""; }), { fireImmediately: true } ); // highlight the tab when the tab document is brushed in any part of the UI - // tab._disposers.reactionDisposer = reaction( - // () => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), - // ({ title, degree }) => { - // titleEle.value = title; - // titleEle.style.padding = degree ? 0 : 2; - // titleEle.style.border = `${['gray', 'gray', 'gray'][degree]} ${['none', 'dashed', 'solid'][degree]} 2px`; - // }, - // { fireImmediately: true } - // ); + tab._disposers.reactionDisposer = reaction( + () => doc?.title, + title => (titleEle.value = title), + { fireImmediately: true } + ); // clean up the tab when it is closed tab.closeElement @@ -346,11 +345,15 @@ export class TabDocView extends React.Component { this.props.glContainer.layoutManager.off('activeContentItemChanged', this.onActiveContentItemChanged); } + // Flag indicating that when a tab is activated, it should not select it's document. + // this is used by the link properties menu when it wants to display the link target without selecting the target (which would make the link property window go away since it would no longer be selected) + public static DontSelectOnActivate = 'dontSelectOnActivate'; + @action.bound private onActiveContentItemChanged(contentItem: any) { if (!contentItem || (this.stack === contentItem.parent && ((contentItem?.tab === this.tab && !this._isActive) || (contentItem?.tab !== this.tab && this._isActive)))) { this._activated = this._isActive = !contentItem || contentItem?.tab === this.tab; - if (!this._view && this.tab?.contentItem?.config?.props?.panelName !== 'dontSelectOnActivate') setTimeout(() => SelectionManager.SelectView(this._view, false)); + if (!this._view && this.tab?.contentItem?.config?.props?.panelName !== TabDocView.DontSelectOnActivate) setTimeout(() => SelectionManager.SelectView(this._view, false)); !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one. } } @@ -365,8 +368,9 @@ export class TabDocView extends React.Component { addDocTab = (doc: Doc, location: OpenWhere) => { SelectionManager.DeselectAll(); const whereFields = location.split(':'); - const keyValue = whereFields[1]?.includes('KeyValue'); - const whereMods: OpenWhereMod = whereFields.length > 1 ? (whereFields[1].replace('KeyValue', '') as OpenWhereMod) : OpenWhereMod.none; + const keyValue = whereFields.includes(OpenWhereMod.keyvalue); + const whereMods = whereFields.length > 1 ? (whereFields[1] as OpenWhereMod) : OpenWhereMod.none; + const panelName = whereFields.length > 1 ? whereFields.lastElement() : ''; if (doc.dockingConfig && !keyValue) return DashboardView.openDashboard(doc); // prettier-ignore switch (whereFields[0]) { @@ -381,8 +385,8 @@ export class TabDocView extends React.Component { } return LightboxView.Instance.AddDocTab(doc, OpenWhere.lightbox); case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods); - case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, whereMods, this.stack, undefined, keyValue); - case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods, this.stack, "dontSelectOnActivate", keyValue); + case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, whereMods, this.stack, panelName, undefined, keyValue); + case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods, this.stack, TabDocView.DontSelectOnActivate, keyValue); case OpenWhere.add:default:return CollectionDockingView.AddSplit(doc, whereMods, this.stack, undefined, keyValue); } }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 57c943479..cafa8b38f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -15,7 +15,7 @@ import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../ import { ImageField } from '../../../../fields/URLField'; import { TraceMobx } from '../../../../fields/util'; import { GestureUtils } from '../../../../pen-gestures/GestureUtils'; -import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils'; import { CognitiveServices } from '../../../cognitive_services/CognitiveServices'; import { Docs, DocUtils } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; @@ -36,7 +36,7 @@ import { GestureOverlay } from '../../GestureOverlay'; import { CtrlKey } from '../../GlobalKeyHandler'; import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke'; import { LightboxView } from '../../LightboxView'; -import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView'; +import { CollectionFreeFormDocumentViewWrapper, CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView'; import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -45,7 +45,6 @@ import { CreateImage } from '../../nodes/WebBoxRenderer'; import { StyleProp } from '../../StyleProvider'; import { CollectionSubView } from '../CollectionSubView'; import { TreeViewType } from '../CollectionTreeView'; -import { TabDocView } from '../TabDocView'; import { CollectionFreeFormBackgroundGrid } from './CollectionFreeFormBackgroundGrid'; import { computePassLayout, computePivotLayout, computeStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines'; import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannableContents'; @@ -86,9 +85,6 @@ export class CollectionFreeFormView extends CollectionSubView(); - private _layoutPoolData = observable.map(); - private _layoutSizeData = observable.map(); - private _cachedPool: Map = new Map(); private _batch: UndoManager.Batch | undefined = undefined; private _brushtimer: any; private _brushtimer1: any; @@ -109,7 +105,10 @@ export class CollectionFreeFormView extends CollectionSubView ele.bounds && !ele.bounds.z && ele.inkMask !== -1 && ele.inkMask !== undefined).map(ele => ele.ele); const renderableEles = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && (ele.inkMask === -1 || ele.inkMask === undefined)).map(ele => ele.ele); if (viewsMask.length) renderableEles.push(
(ele.inkMask ?? 0) > 0) ? '' : '-empty'}`}>{viewsMask}
); @@ -637,7 +636,8 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).filter(doc => doc instanceof Doc); const measuredDocs = docs - .map(doc => ({ pos: this.childPositionProviderUnmemoized(doc, ''), size: this.childSizeProviderUnmemoized(doc, '') })) + .map(doc => ({ pos: { x: NumCast(doc.x), y: NumCast(doc.y) }, size: { width: NumCast(doc.width), height: NumCast(doc.height) } })) .filter(({ pos, size }) => pos && size) .map(({ pos, size }) => ({ pos: pos!, size: size! })); if (measuredDocs.length) { @@ -1247,7 +1247,6 @@ export class CollectionFreeFormView extends CollectionSubView this._layoutPoolData.get(doc[Id] + (replica || '')); - childDataProvider = computedFn( - function childDataProvider(this: any, doc: Doc, replica: string) { - return this.childPositionProviderUnmemoized(doc, replica); - }.bind(this) - ); - - childSizeProviderUnmemoized = (doc: Doc, replica: string) => this._layoutSizeData.get(doc[Id] + (replica || '')); - childSizeProvider = computedFn( - function childSizeProvider(this: any, doc: Doc, replica: string) { - return this.childSizeProviderUnmemoized(doc, replica); - }.bind(this) - ); - doEngineLayout( poolData: Map, engine: (poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) => ViewDefResult[] @@ -1467,46 +1452,18 @@ export class CollectionFreeFormView extends CollectionSubView, computedElementData: ViewDefResult[]) => { - const array = Array.from(newPool.entries()); - for (const entry of array) { - const lastPos = this._cachedPool.get(entry[0]); // last computed pos - const newPos = entry[1]; - if ( - !lastPos || - newPos.color !== lastPos.color || - newPos.backgroundColor !== lastPos.backgroundColor || - newPos.opacity !== lastPos.opacity || - newPos.x !== lastPos.x || - newPos.y !== lastPos.y || - newPos.z !== lastPos.z || - newPos.rotation !== lastPos.rotation || - newPos.zIndex !== lastPos.zIndex || - newPos.transition !== lastPos.transition || - newPos.pointerEvents !== lastPos.pointerEvents - ) { - this._layoutPoolData.set(entry[0], newPos); - } - if (!lastPos || newPos.height !== lastPos.height || newPos.width !== lastPos.width) { - this._layoutSizeData.set(entry[0], { width: newPos.width, height: newPos.height }); - } - } - this._cachedPool.clear(); - Array.from(newPool.entries()).forEach(k => this._cachedPool.set(k[0], k[1])); const elements = computedElementData.slice(); Array.from(newPool.entries()) .filter(entry => this.isCurrent(entry[1].pair.layout)) - .forEach((entry, i) => { - const childData: ViewDefBounds = this.childDataProvider(entry[1].pair.layout, entry[1].replica); - const childSize = this.childSizeProvider(entry[1].pair.layout, entry[1].replica); + .forEach(entry => elements.push({ ele: this.getChildDocView(entry[1]), - bounds: childData.opacity === 0 ? { ...childData, width: 0, height: 0 } : { ...childData, width: childSize.width, height: childSize.height }, + bounds: (entry[1].opacity === 0 ? { ...entry[1], width: 0, height: 0 } : { ...entry[1] }) as any, inkMask: BoolCast(entry[1].pair.layout.stroke_isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1, - }); - }); + }) + ); this.Document._freeform_useClusters && !this._clusterSets.length && this.childDocs.length && this.updateClusters(true); return elements; @@ -1580,12 +1537,6 @@ export class CollectionFreeFormView extends CollectionSubView this.doInternalLayoutComputation, - ({ newPool, computedElementData }) => (this._layoutElements = this.doLayoutComputation(newPool, computedElementData)), - { fireImmediately: true, name: 'layoutComputationReaction' } - ); - this._disposers.active = reaction( () => this.isContentActive(), // if autoreset is on, then whenever the view is selected, it will be restored to it default pan/zoom positions active => !SnappingManager.GetIsDragging() && this.rootDoc[this.autoResetFieldKey] && active && this.resetView() @@ -1752,7 +1703,7 @@ export class CollectionFreeFormView extends CollectionSubView (Doc.UserDoc().defaultTextLayout = undefined), icon: 'eye' }); - appearanceItems.push({ description: `Pin View`, event: () => TabDocView.PinDoc(this.rootDoc, { pinViewport: MarqueeView.CurViewBounds(this.rootDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' }); + appearanceItems.push({ description: `Pin View`, event: () => this.props.pinToPres(this.rootDoc, { pinViewport: MarqueeView.CurViewBounds(this.rootDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' }); !Doc.noviceMode && appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: 'compress-arrows-alt' }); this.props.renderDepth && appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' }); @@ -1799,13 +1750,10 @@ export class CollectionFreeFormView extends CollectionSubView()) => { + dragStarting = (snapToDraggedDoc: boolean = false, showGroupDragTarget: boolean = true, visited = new Set()) => { if (visited.has(this.rootDoc)) return; visited.add(this.rootDoc); showGroupDragTarget && (this.GroupChildDrag = BoolCast(this.Document._isGroup)); - if (this.rootDoc._isGroup && this.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView) { - this.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView.dragStarting(snapToDraggedDoc, false, visited); - } const activeDocs = this.getActiveDocuments(); const size = this.screenToLocalXf.transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] }; @@ -1813,13 +1761,9 @@ export class CollectionFreeFormView extends CollectionSubView intersectRect(docDims(doc), rect); const snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to - activeDocs.forEach( - doc => - doc._isGroup && - SnappingManager.GetIsResizing() !== doc && - !DragManager.docsBeingDragged.includes(doc) && - (DocumentManager.Instance.getDocumentView(doc)?.ComponentView as CollectionFreeFormView)?.dragStarting(snapToDraggedDoc, false, visited) - ); + activeDocs + .filter(doc => doc._isGroup && SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc)) + .forEach(doc => DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.dragStarting?.(snapToDraggedDoc, false, visited)); const horizLines: number[] = []; const vertLines: number[] = []; @@ -1850,10 +1794,11 @@ export class CollectionFreeFormView extends CollectionSubView !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1); }); - get children() { - this.incrementalRender(); - const children = typeof this.props.children === 'function' ? ((this.props.children as any)() as JSX.Element[]) : this.props.children ? [this.props.children] : []; - return [...children, ...this.views, ]; + // if a freeform view has any children, then the children will likely consist of a single child + // which will be a DocumentView. In this sitation, this freeform views acts as an annotation overlay for + // the underlying DocumentView and will pan and scoll with the underlying Documen tView. + @computed get underlayViews() { + return this.props.children ? [this.props.children] : []; } @computed get placeholder() { @@ -1889,6 +1834,7 @@ export class CollectionFreeFormView extends CollectionSubView - {this.children} + {this.underlayViews} + {this.contentViews} + ); } @@ -2048,11 +1996,11 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY if (!focused) { const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; let containers = dv.props.docViewPath(); - let parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + let parFfview = dv.CollectionFreeFormView; for (var cont of containers) { - parFfview = parFfview ?? cont.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + parFfview = parFfview ?? cont.CollectionFreeFormView; } - while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView; const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview ffview?.zoomSmoothlyAboutPt(ffview.screenToLocalXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); Doc.linkFollowHighlight(dv?.props.Document, false); @@ -2084,8 +2032,8 @@ ScriptingGlobals.add(function pinWithView(pinContent: boolean) { ); }); ScriptingGlobals.add(function bringToFront() { - SelectionManager.Views().forEach(view => view.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView.bringToFront(view.rootDoc)); + SelectionManager.Views().forEach(view => view.CollectionFreeFormView?.bringToFront(view.rootDoc)); }); ScriptingGlobals.add(function sendToBack(doc: Doc) { - SelectionManager.Views().forEach(view => view.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView.bringToFront(view.rootDoc, true)); + SelectionManager.Views().forEach(view => view.CollectionFreeFormView?.bringToFront(view.rootDoc, true)); }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index f831478a7..23f9bc69e 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -22,7 +22,6 @@ import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { pasteImageBitmap } from '../../nodes/WebBoxRenderer'; import { PreviewCursor } from '../../PreviewCursor'; import { SubCollectionViewProps } from '../CollectionSubView'; -import { TabDocView } from '../TabDocView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; import React = require('react'); @@ -212,14 +211,15 @@ export class MarqueeView extends React.Component { - TabDocView.PinDoc(this.props.Document, { pinViewport: this.Bounds }); + this.props.pinToPres(this.props.Document, { pinViewport: this.Bounds }); MarqueeOptionsMenu.Instance.fadeOut(true); this.hideMarquee(); }; diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index d2df58102..c690b8623 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -93,7 +93,7 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) { if (NumCast(selected?.Document.z) >= 1) return true; return false; } - selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log('[FontIconBox.tsx] toggleOverlay failed'); + selected ? selected.CollectionFreeFormDocumentView?.float() : console.log('[FontIconBox.tsx] toggleOverlay failed'); }); ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce', checkResult?: boolean) { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.scss b/src/client/views/nodes/CollectionFreeFormDocumentView.scss index f99011b8f..7f0a39550 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.scss +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.scss @@ -1,9 +1,9 @@ .collectionFreeFormDocumentView-container { - transform-origin: left top; + transform-origin: 50% 50%; position: absolute; background-color: transparent; touch-action: manipulation; top: 0; left: 0; - //pointer-events: none; + pointer-events: none; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 09dfa4f99..a05d6c904 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable } from 'mobx'; +import { action, computed, observable, trace } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; @@ -6,10 +6,9 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField } from '../../../fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { numberRange } from '../../../Utils'; +import { numberRange, OmitKeys } from '../../../Utils'; import { DocumentManager } from '../../util/DocumentManager'; import { SelectionManager } from '../../util/SelectionManager'; -import { Transform } from '../../util/Transform'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { DocComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; @@ -17,18 +16,102 @@ import './CollectionFreeFormDocumentView.scss'; import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; import React = require('react'); -export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { - dataProvider: (doc: Doc, replica: string) => { x: number; y: number; zIndex?: number; rotation?: number; color?: string; backgroundColor?: string; opacity?: number; highlight?: boolean; z: number; transition?: string }; - sizeProvider: (doc: Doc, replica: string) => { width: number; height: number }; - renderCutoffProvider: (doc: Doc) => boolean; +export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentViewProps { + x: number; + y: number; + z: number; + width: number; + height: number; zIndex?: number; + rotation?: number; + color?: string; + backgroundColor?: string; + opacity?: number; + highlight?: boolean; + transition?: string; dataTransition?: string; - replica: string; + RenderCutoffProvider: (doc: Doc) => boolean; + CollectionFreeFormView: CollectionFreeFormView; +} +@observer +export class CollectionFreeFormDocumentViewWrapper extends DocComponent() implements CollectionFreeFormDocumentViewProps { + @observable X = this.props.x; + @observable Y = this.props.y; + @observable Z = this.props.z; + @observable ZIndex = this.props.zIndex; + @observable Rotation = this.props.rotation; + @observable Opacity = this.props.opacity; + @observable BackgroundColor = this.props.backgroundColor; + @observable Color = this.props.color; + @observable Highlight = this.props.highlight; + @observable Width = this.props.width; + @observable Height = this.props.height; + @observable Transition = this.props.transition; + @observable DataTransition = this.props.dataTransition; + CollectionFreeFormView = this.props.CollectionFreeFormView; // needed for type checking + RenderCutoffProvider = this.props.RenderCutoffProvider; // needed for type checking + + @computed get WrapperKeys() { + return Object.keys(this).filter(key => key.startsWith('w_')).map(key => key.replace('w_', '')) + .map(key => ({upper:key, lower:key[0].toLowerCase() + key.substring(1)})); // prettier-ignore + } + + // wrapper functions around prop fields that have been converted to observables to keep 'props' from ever changing. + // this way, downstream code only invalidates when it uses a specific prop, not when any prop changes + w_X = () => this.X; // prettier-ignore + w_Y = () => this.Y; // prettier-ignore + w_Z = () => this.Z; // prettier-ignore + w_ZIndex = () => this.ZIndex ?? NumCast(this.props.Document.zIndex); // prettier-ignore + w_Rot = () => this.Rotation ?? NumCast(this.props.Document._rotation); // prettier-ignore + w_Opacity = () => this.Opacity; // prettier-ignore + w_BackgroundColor = () => this.BackgroundColor ?? Cast(this.props.Document._backgroundColor, 'string', null); // prettier-ignore + w_Color = () => this.Color ?? Cast(this.props.Document._color, 'string', null); // prettier-ignore + w_Highlight = () => this.Highlight; // prettier-ignore + w_Width = () => this.Width; // prettier-ignore + w_Height = () => this.Height; // prettier-ignore + w_Transition = () => this.Transition; // prettier-ignore + w_DataTransition = () => this.DataTransition; // prettier-ignore + + PanelWidth = () => this.Width || this.props.PanelWidth?.(); // prettier-ignore + PanelHeight = () => this.Height || this.props.PanelHeight?.(); // prettier-ignore + @action + componentDidUpdate() { + this.WrapperKeys.forEach(keys => ((this as any)[keys.upper] = (this.props as any)[keys.lower])); + } + render() { + const layoutProps = this.WrapperKeys.reduce((val, keys) => [(val['w_' + keys.upper] = (this as any)['w_' + keys.upper]), val][1], {} as { [key: string]: Function }); + return ( + keys.lower) ).omit} // prettier-ignore + {...layoutProps} + PanelWidth={this.PanelWidth} + PanelHeight={this.PanelHeight} + /> + ); + } +} +export interface CollectionFreeFormDocumentViewProps { + w_X: () => number; + w_Y: () => number; + w_Z: () => number; + w_ZIndex?: () => number; + w_Rotation?: () => number; + w_Color: () => string; + w_BackgroundColor: () => string; + w_Opacity: () => number | undefined; + w_Highlight: () => boolean | undefined; + w_Transition: () => string | undefined; + w_Width: () => number; + w_Height: () => number; + w_DataTransition: () => string | undefined; + PanelWidth: () => number; + PanelHeight: () => number; + RenderCutoffProvider: (doc: Doc) => boolean; CollectionFreeFormView: CollectionFreeFormView; } @observer -export class CollectionFreeFormDocumentView extends DocComponent() { +export class CollectionFreeFormDocumentView extends DocComponent() { get displayName() { // this makes mobx trace() statements more descriptive return 'CollectionFreeFormDocumentView(' + this.rootDoc.title + ')'; } // prettier-ignore @@ -48,26 +131,19 @@ export class CollectionFreeFormDocumentView extends DocComponent (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames - get X() { return this.dataProvider.x; } // prettier-ignore - get Y() { return this.dataProvider.y; } // prettier-ignore - get ZInd() { return this.dataProvider.zIndex ?? NumCast(this.Document.zIndex); } // prettier-ignore - get Rot() { return this.dataProvider.rotation ?? NumCast(this.Document._rotation); } // prettier-ignore - get Opacity() { return this.dataProvider.opacity; } // prettier-ignore - get BackgroundColor() { return this.dataProvider.backgroundColor ?? Cast(this.Document._backgroundColor, 'string', null); } // prettier-ignore - get Color() { return this.dataProvider.color ?? Cast(this.Document._color, 'string', null); } // prettier-ignore - @observable _animPos: number[] | undefined = undefined; @observable _contentView: DocumentView | undefined | null; - @computed get dataProvider() { return this.props.dataProvider(this.props.Document, this.props.replica); } // prettier-ignore - @computed get sizeProvider() { return this.props.sizeProvider(this.props.Document, this.props.replica); } // prettier-ignore + get CollectionFreeFormView() { + return this.props.CollectionFreeFormView; + } styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (doc === this.layoutDoc) { switch (property) { - case StyleProp.Opacity: return this.Opacity; // only change the opacity for this specific document, not its children - case StyleProp.BackgroundColor: return this.BackgroundColor; - case StyleProp.Color: return this.Color; + case StyleProp.Opacity: return this.props.w_Opacity(); // only change the opacity for this specific document, not its children + case StyleProp.BackgroundColor: return this.props.w_BackgroundColor(); + case StyleProp.Color: return this.props.w_Color(); } // prettier-ignore } return this.props.styleProvider?.(doc, props, property); @@ -146,16 +222,11 @@ export class CollectionFreeFormDocumentView extends DocComponent this.props.CollectionFreeFormView?.dragEnding(); - dragStarting = () => this.props.CollectionFreeFormView?.dragStarting(false, true); - nudge = (x: number, y: number) => { - this.props.Document.x = NumCast(this.props.Document.x) + x; - this.props.Document.y = NumCast(this.props.Document.y) + y; + this.props.Document.x = this.props.w_X() + x; + this.props.Document.y = this.props.w_Y() + y; }; - panelWidth = () => this.sizeProvider?.width || this.props.PanelWidth?.(); - panelHeight = () => this.sizeProvider?.height || this.props.PanelHeight?.(); - screenToLocalTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.X, -this.Y); + screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(-this.props.w_X(), -this.props.w_Y()); returnThis = () => this; /// this indicates whether the doc view is activated because of its relationshop to a group @@ -164,38 +235,35 @@ export class CollectionFreeFormDocumentView extends DocComponent { - if (this.props.CollectionFreeFormView.isAnyChildContentActive()) return undefined; + if (this.CollectionFreeFormView.isAnyChildContentActive()) return undefined; const isGroup = this.rootDoc._isGroup && (!this.rootDoc.backgroundColor || this.rootDoc.backgroundColor === 'transparent'); return isGroup ? (this.props.isDocumentActive?.() ? 'group' : this.props.isGroupActive?.() ? 'child' : 'inactive') : this.props.isGroupActive?.() ? 'child' : undefined; }; render() { TraceMobx(); - const divProps: DocumentViewProps = { - ...this.props, - CollectionFreeFormDocumentView: this.returnThis, - styleProvider: this.styleProvider, - ScreenToLocalTransform: this.screenToLocalTransform, - PanelWidth: this.panelWidth, - PanelHeight: this.panelHeight, - isGroupActive: this.isGroupActive, - }; + const passOnProps = OmitKeys(this.props, Object.keys(this.props).filter(key => key.startsWith('w_'))).omit; // prettier-ignore return (
- {this.props.renderCutoffProvider(this.props.Document) ? ( -
+ {this.props.RenderCutoffProvider(this.props.Document) ? ( +
) : ( - (this._contentView = r))} /> + (this._contentView = r))} + {...passOnProps} + CollectionFreeFormDocumentView={this.returnThis} + styleProvider={this.styleProvider} + ScreenToLocalTransform={this.screenToLocalTransform} + isGroupActive={this.isGroupActive} + /> )}
); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index e1de2fa76..c4703a47c 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -98,7 +98,7 @@ export class HTMLtag extends React.Component { }; render() { const style: { [key: string]: any } = {}; - const divKeys = OmitKeys(this.props, ['children', 'htmltag', 'RootDoc', 'scaling', 'Document', 'key', 'onInput', 'onClick', '__proto__']).omit; + const divKeys = OmitKeys(this.props, ['children', 'dragStarting', 'dragEnding', 'htmltag', 'RootDoc', 'scaling', 'Document', 'key', 'onInput', 'onClick', '__proto__']).omit; const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a propery expression string: { script } into a value return (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ self: this.props.RootDoc, this: this.props.Document, scale: this.props.scaling }).result as string) || ''; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4dba5cbd3..005ec6019 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -64,6 +64,14 @@ declare class MediaRecorder { constructor(e: any); } +export enum OpenWhereMod { + none = '', + left = 'left', + right = 'right', + top = 'top', + bottom = 'bottom', + keyvalue = 'keyValue', +} export enum OpenWhere { lightbox = 'lightbox', add = 'add', @@ -79,14 +87,7 @@ export enum OpenWhere { inParent = 'inParent', inParentFromScreen = 'inParentFromScreen', overlay = 'overlay', -} -export enum OpenWhereMod { - none = '', - left = 'left', - right = 'right', - top = 'top', - bottom = 'bottom', - rightKeyValue = 'rightKeyValue', + addRightKeyvalue = 'add:right:keyValue', } export interface DocFocusOptions { @@ -134,6 +135,7 @@ export interface DocComponentView { setFocus?: () => void; // sets input focus to the componentView setData?: (data: Field | Promise) => boolean; componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null; + dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set) => void; incrementalRendering?: () => void; layout_fitWidth?: () => boolean; // whether the component always fits width (eg, KeyValueBox) overridePointerEvents?: () => 'all' | 'none' | undefined; // if the conmponent overrides the pointer events for the document (e.g, KeyValueBox always allows pointer events) @@ -166,7 +168,6 @@ export interface DocumentViewSharedProps { childHideDecorationTitle?: () => boolean; childHideResizeHandles?: () => boolean; childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar. - dataTransition?: string; // specifies animation transition - used by collectionPile and potentially other layout engines when changing the size of documents so that the change won't be abrupt styleProvider: Opt; setTitleFocus?: () => void; focus: DocFocusFunc; @@ -235,6 +236,8 @@ export interface DocumentViewProps extends DocumentViewSharedProps { onPointerUp?: () => ScriptField; onBrowseClick?: () => ScriptField | undefined; onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined; + dragStarting?: () => void; + dragEnding?: () => void; } // these props are only available in DocumentViewIntenral @@ -321,7 +324,6 @@ export class DocumentViewInternal extends DocComponent LightboxView.Instance.SetLightboxDoc(this.rootDoc), icon: 'external-link-alt' }); } + this.rootDoc.type === DocumentType.PRES && appearanceItems.push({ description: 'Pin', event: () => this.props.pinToPres(this.rootDoc, {}), icon: 'eye' }); !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !appearance && appearanceItems.length && cm.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'compass' }); @@ -841,7 +843,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(this.props.Document, (OpenWhere.addRight.toString() + 'KeyValue') as OpenWhere), icon: 'table-columns' }); + constantItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(this.props.Document, OpenWhere.addRightKeyvalue), icon: 'table-columns' }); cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' }); const help = cm.findByDescription('Help...'); @@ -1519,6 +1521,13 @@ export class DocumentView extends React.Component { return this.props.dontCenter?.includes('y') ? 0 : this.Yshift; } + @computed get CollectionFreeFormView() { + return this.CollectionFreeFormDocumentView?.CollectionFreeFormView; + } + @computed get CollectionFreeFormDocumentView() { + return this.props.CollectionFreeFormDocumentView?.(); + } + public toggleNativeDimensions = () => this.docView && this.rootDoc.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); public getBounds = () => { if (!this.docView?.ContentDiv || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { @@ -1667,7 +1676,7 @@ export class DocumentView extends React.Component { className="contentFittingDocumentView-previewDoc" ref={this.ContentRef} style={{ - transition: this.props.dataTransition, + transition: 'inherit', // this.props.dataTransition, transform: `translate(${this.centeringX}px, ${this.centeringY}px)`, width: xshift ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`, height: this.props.forceAutoHeight diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index f22cb195f..6f99b7c28 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -7,7 +7,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { EditableView } from '../EditableView'; import { DefaultStyleProvider } from '../StyleProvider'; -import { OpenWhere } from './DocumentView'; +import { OpenWhere, OpenWhereMod } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; import './KeyValueBox.scss'; @@ -50,7 +50,7 @@ export class KeyValuePair extends React.Component { if (value instanceof Doc) { e.stopPropagation(); e.preventDefault(); - ContextMenu.Instance.addItem({ description: 'Open Fields', event: () => this.props.addDocTab(value, ((OpenWhere.addRight as string) + 'KeyValue') as OpenWhere), icon: 'layer-group' }); + ContextMenu.Instance.addItem({ description: 'Open Fields', event: () => this.props.addDocTab(value, OpenWhere.addRightKeyvalue), icon: 'layer-group' }); ContextMenu.Instance.displayMenu(e.clientX, e.clientY); } }; diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 034eb4011..416cb11cc 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -32,7 +32,7 @@ export class LinkBox extends ViewBoxBaseComponent() { return DocumentManager.Instance.getDocumentView(anchor_2, this.props.docViewPath()[this.props.docViewPath().length - 2]); // this.props.docViewPath().lastElement()); } screenBounds = () => { - if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView) { + if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) { const a_invXf = this.anchor1.props.ScreenToLocalTransform().inverse(); const b_invXf = this.anchor2.props.ScreenToLocalTransform().inverse(); const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(this.anchor1.rootDoc._width), NumCast(this.anchor1.rootDoc._height)) }; @@ -57,7 +57,7 @@ export class LinkBox extends ViewBoxBaseComponent() { this.props.setContentView?.(this); this.disposer = reaction( () => { - if (this.layoutDoc._layout_isSvg && (this.anchor1 || this.anchor2)?.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView) { + if (this.layoutDoc._layout_isSvg && (this.anchor1 || this.anchor2)?.CollectionFreeFormView) { const a = (this.anchor1 ?? this.anchor2)!; const b = (this.anchor2 ?? this.anchor1)!; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index c4ef07123..180fa9f5d 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -27,7 +27,6 @@ import { CollectionDockingView } from '../../collections/CollectionDockingView'; import { CollectionFreeFormView, computeTimelineLayout, MarqueeViewBounds } from '../../collections/collectionFreeForm'; import { CollectionStackedTimeline } from '../../collections/CollectionStackedTimeline'; import { CollectionView } from '../../collections/CollectionView'; -import { TabDocView } from '../../collections/TabDocView'; import { TreeView } from '../../collections/TreeView'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; @@ -439,7 +438,7 @@ export class PresBox extends ViewBoxBaseComponent() { const acontext = activeItem.config_activeFrame !== undefined ? DocCast(DocCast(activeItem.presentation_targetDoc).embedContainer) : DocCast(activeItem.presentation_targetDoc); const context = DocCast(acontext)?.annotationOn ? DocCast(DocCast(acontext).annotationOn) : acontext; if (context) { - const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.CollectionFreeFormView; if (ffview?.childDocs) { PresBox.Instance._keyTimer = CollectionFreeFormView.gotoKeyframe(PresBox.Instance._keyTimer, ffview.childDocs, transTime); ffview.rootDoc._currentFrame = NumCast(activeFrame); @@ -768,6 +767,8 @@ export class PresBox extends ViewBoxBaseComponent() { PresBox.NavigateToTarget(targetDoc, activeItem, resetSelection); }; + public static PanelName = 'PRESBOX'; + static NavigateToTarget(targetDoc: Doc, activeItem: Doc, finished?: () => void) { if (activeItem.presentation_movement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.(); @@ -782,7 +783,7 @@ export class PresBox extends ViewBoxBaseComponent() { zoomTime: activeItem.presentation_movement === PresMovement.Jump ? 0 : Math.min(Math.max(effect ? 750 : 500, (effect ? 0.2 : 1) * presTime), presTime), effect: activeItem, noSelect: true, - openLocation: OpenWhere.addLeft, + openLocation: targetDoc.type === DocumentType.PRES ? ((OpenWhere.replace + ':' + PresBox.PanelName) as OpenWhere) : OpenWhere.addLeft, anchorDoc: activeItem, easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any, zoomTextSelections: BoolCast(activeItem.presentation_zoomText), @@ -1068,7 +1069,7 @@ export class PresBox extends ViewBoxBaseComponent() { audio.config_clipStart = NumCast(doc._timecodeToShow /* audioStart */, NumCast(doc._timecodeToShow /* videoStart */)); audio.config_clipEnd = NumCast(doc._timecodeToHide /* audioEnd */, NumCast(doc._timecodeToHide /* videoEnd */)); audio.presentation_duration = audio.config_clipStart - audio.config_clipEnd; - TabDocView.PinDoc(audio, { audioRange: true }); + this.props.pinToPres(audio, { audioRange: true }); setTimeout(() => this.removeDocument(doc), 0); return false; } @@ -2223,7 +2224,7 @@ export class PresBox extends ViewBoxBaseComponent() { const config_data = Cast(this.rootDoc.data, listSpec(Doc)); if (data && config_data) { data.push(doc); - TabDocView.PinDoc(doc, {}); + this.props.pinToPres(doc, {}); this.gotoDocument(this.childDocs.length, this.activeItem); } else { this.props.addDocTab(doc, OpenWhere.addRight); -- cgit v1.2.3-70-g09d2 From 0dc39baf9630ae5aeaa41b89523ec6bf96d0b198 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Nov 2023 21:53:36 -0500 Subject: major overhaul of resizing code. updated doc fields for enabling native with modification to be cleaner. added Vcenter option for text in menu bar. fixed doc rotation. enabled scaling of DataViz views. fixed text sidebar opening size and sidebar issues with native dims for PDF/Web --- src/client/documents/Documents.ts | 43 +-- src/client/util/CurrentUserUtils.ts | 4 +- src/client/views/DocumentDecorations.tsx | 312 +++++++++------------ src/client/views/InkControlPtHandles.tsx | 7 +- src/client/views/MainView.tsx | 1 + .../CollectionMulticolumnView.tsx | 2 +- .../CollectionMultirowView.tsx | 2 +- src/client/views/global/globalScripts.ts | 14 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 10 +- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 13 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 6 +- src/fields/Doc.ts | 6 - 15 files changed, 191 insertions(+), 237 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1ea9b1dcc..bd5fa5d78 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -186,8 +186,6 @@ export class DocumentOptions { linearBtnWidth?: NUMt = new NumInfo('unexpanded width of a linear menu button (button "width" changes when it expands)', false); _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)', false); _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)', false); - _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false); - _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers'); 'acl-Guest'?: STRt = new StrInfo("permissions granted to users logged in as 'guest' (either view, or private)"); // public permissions '_acl-Guest'?: string; // public permissions @@ -229,12 +227,16 @@ export class DocumentOptions { layout_hideLinkButton?: BOOLt = new BoolInfo('whether the blue link counter button should be hidden'); layout_hideDecorationTitle?: BOOLt = new BoolInfo('whether to suppress the document decortations title when selected'); layout_borderRounding?: string; + _layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false); + _layout_reflowVertical?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers'); + _layout_reflowHorizontal?: BOOLt = new BoolInfo('whether a doc with a native size can be horizonally resized, causing some form of reflow'); layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow layout_maxAutoHeight?: NUMt = new NumInfo('maximum height for newly created (eg, from pasting) text documents', false); _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents'); _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document', false); _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video) value is in seconds', false); _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown'); + _layout_centered?: BOOLt = new BoolInfo('whether text should be vertically centered in Doc'); _layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)'); _layout_fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content'); _layout_fieldKey?: STRt = new StrInfo('the field key containing the current layout definition', false); @@ -472,9 +474,9 @@ export namespace Docs { _height: 35, _xMargin: 10, _yMargin: 10, - nativeDimModifiable: true, - nativeHeightUnfrozen: true, - layout_forceReflow: true, + layout_nativeDimEditable: true, + layout_reflowVertical: true, + layout_reflowHorizontal: true, defaultDoubleClick: 'ignore', systemIcon: 'BsFileEarmarkTextFill', }, @@ -505,7 +507,7 @@ export namespace Docs { DocumentType.WEB, { layout: { view: WebBox, dataField: defaultDataKey }, - options: { _height: 300, _layout_fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, waitForDoubleClickToClick: 'always', systemIcon: 'BsGlobe' }, + options: { _height: 300, _layout_fitWidth: true, layout_nativeDimEditable: true, layout_reflowVertical: true, waitForDoubleClickToClick: 'always', systemIcon: 'BsGlobe' }, }, ], [ @@ -533,7 +535,7 @@ export namespace Docs { DocumentType.AUDIO, { layout: { view: AudioBox, dataField: defaultDataKey }, - options: { _height: 100, layout_fitWidth: true, layout_forceReflow: true, nativeDimModifiable: true, systemIcon: 'BsFillVolumeUpFill' }, + options: { _height: 100, layout_fitWidth: true, layout_reflowHorizontal: true, layout_nativeDimEditable: true, systemIcon: 'BsFillVolumeUpFill' }, }, ], [ @@ -547,14 +549,14 @@ export namespace Docs { DocumentType.PDF, { layout: { view: PDFBox, dataField: defaultDataKey }, - options: { _layout_curPage: 1, _layout_fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, systemIcon: 'BsFileEarmarkPdfFill' }, + options: { _layout_curPage: 1, _layout_fitWidth: true, layout_nativeDimEditable: true, layout_reflowVertical: true, systemIcon: 'BsFileEarmarkPdfFill' }, }, ], [ DocumentType.MAP, { layout: { view: MapBox, dataField: defaultDataKey }, - options: { map: '', _height: 600, _width: 800, nativeDimModifiable: true, systemIcon: 'BsFillPinMapFill' }, + options: { map: '', _height: 600, _width: 800, layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true, systemIcon: 'BsFillPinMapFill' }, }, ], [ @@ -613,14 +615,14 @@ export namespace Docs { DocumentType.EQUATION, { layout: { view: EquationBox, dataField: 'text' }, - options: { nativeDimModifiable: true, fontSize: '14px', layout_hideResizeHandles: true, layout_hideDecorationTitle: true, systemIcon: 'BsCalculatorFill' }, ///systemIcon: 'BsSuperscript' + BsSubscript + options: { layout_nativeDimEditable: true, fontSize: '14px', layout_hideResizeHandles: true, layout_hideDecorationTitle: true, systemIcon: 'BsCalculatorFill' }, ///systemIcon: 'BsSuperscript' + BsSubscript }, ], [ DocumentType.FUNCPLOT, { layout: { view: FunctionPlotBox, dataField: defaultDataKey }, - options: { nativeDimModifiable: true }, + options: { layout_nativeDimEditable: true }, }, ], [ @@ -672,12 +674,12 @@ export namespace Docs { layout: { view: InkingStroke, dataField: 'stroke' }, options: { systemIcon: 'BsFillPencilFill', // - nativeDimModifiable: true, - nativeHeightUnfrozen: true, + layout_nativeDimEditable: true, + layout_reflowVertical: true, + layout_reflowHorizontal: true, layout_hideDecorationTitle: true, // don't show title when selected fitWidth: false, layout_isSvg: true, - layout_forceReflow: true, }, }, ], @@ -685,7 +687,7 @@ export namespace Docs { DocumentType.SCREENSHOT, { layout: { view: ScreenshotBox, dataField: defaultDataKey }, - options: { nativeDimModifiable: true, nativeHeightUnfrozen: true, systemIcon: 'BsCameraFill' }, + options: { layout_nativeDimEditable: true, systemIcon: 'BsCameraFill' }, }, ], [ @@ -714,14 +716,14 @@ export namespace Docs { DocumentType.DATAVIZ, { layout: { view: DataVizBox, dataField: defaultDataKey }, - options: { dataViz_title: '', dataViz_line: '', dataViz_pie: '', dataViz_histogram: '', dataViz: 'table', _layout_fitWidth: true, nativeDimModifiable: true }, + options: { dataViz_title: '', dataViz_line: '', dataViz_pie: '', dataViz_histogram: '', dataViz: 'table', _layout_fitWidth: true, layout_reflowHorizontal: true, layout_reflowVertical: true, layout_nativeDimEditable: true }, }, ], [ DocumentType.LOADING, { layout: { view: LoadingBox, dataField: '' }, - options: { _layout_fitWidth: true, _fitHeight: true, nativeDimModifiable: true }, + options: { _layout_fitWidth: true, _fitHeight: true, layout_nativeDimEditable: true }, }, ], [ @@ -731,11 +733,9 @@ export namespace Docs { layout: { view: PhysicsSimulationBox, dataField: defaultDataKey, _width: 1000, _height: 800 }, options: { _height: 100, - layout_forceReflow: true, - nativeHeightUnfrozen: true, mass1: '', mass2: '', - nativeDimModifiable: true, + layout_nativeDimEditable: true, position: '', acceleration: '', pendulum: '', @@ -948,7 +948,7 @@ export namespace Docs { export function ImageDocument(url: string | ImageField, options: DocumentOptions = {}, overwriteDoc?: Doc) { const imgField = url instanceof ImageField ? url : new ImageField(url); - return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { _nativeDimModifiable: false, _nativeHeightUnfrozen: false, title: basename(imgField.url.href), ...options }, undefined, undefined, undefined, overwriteDoc); + return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(imgField.url.href), ...options }, undefined, undefined, undefined, overwriteDoc); } export function PresDocument(options: DocumentOptions = {}) { @@ -1864,6 +1864,7 @@ export namespace DocUtils { _height: 35, x: x, y: y, + _layout_centered: BoolCast(Doc.UserDoc().layout_centered), _layout_fitWidth: true, _layout_autoHeight: true, _layout_enableAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards), diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index cd19daee5..ac506e2d6 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -655,13 +655,13 @@ export class CurrentUserUtils { { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, + { title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "Align", toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true, subMenu: [ { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }}, { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - ] - }, + ]}, { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}}, { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}}, // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}}, diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 33886e791..8df5740fa 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -2,18 +2,17 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { IconButton } from 'browndash-components'; -import { action, computed, observable, reaction } from 'mobx'; +import { action, computed, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { FaUndo } from 'react-icons/fa'; -import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols'; import { InkField } from '../../fields/InkField'; import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; -import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; +import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { GetEffectiveAcl } from '../../fields/util'; -import { aggregateBounds, emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils'; +import { emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils'; import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentManager } from '../util/DocumentManager'; @@ -36,6 +35,7 @@ import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { ImageBox } from './nodes/ImageBox'; import React = require('react'); import _ = require('lodash'); +import { DateField } from '../../fields/DateField'; @observer export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> { @@ -46,11 +46,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P private _linkBoxHeight = 20 + 3; // link button height + margin private _titleHeight = 20; private _resizeUndo?: UndoManager.Batch; - private _offX = 0; - private _offY = 0; // offset from click pt to inner edge of resize border - private _snapX = 0; - private _snapY = 0; // last snapped location of resize border - private _dragHeights = new Map(); + private _offset = { x: 0, y: 0 }; // offset from click pt to inner edge of resize border + private _snapPt = { x: 0, y: 0 }; // last snapped location of resize border private _inkDragDocs: { doc: Doc; x: number; y: number; width: number; height: number }[] = []; @observable private _accumulatedTitle = ''; @@ -479,29 +476,24 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P DocumentView.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them this._resizeHdlId = e.currentTarget.className; const bounds = e.currentTarget.getBoundingClientRect(); - this._offX = this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX; - this._offY = this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY; + this._offset = { x: this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX, y: this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY }; this._resizeUndo = UndoManager.StartBatch('drag resizing'); - this._snapX = e.pageX; - this._snapY = e.pageY; - const ffviewSet = new Set(); - SelectionManager.Views().forEach(docView => { - docView.CollectionFreeFormView && ffviewSet.add(docView.CollectionFreeFormView); - this._dragHeights.set(docView.layoutDoc, { start: NumCast(docView.rootDoc._height), lowest: NumCast(docView.rootDoc._height) }); - }); - Array.from(ffviewSet).map(ffview => ffview.dragStarting(false, false)); + this._snapPt = { x: e.pageX, y: e.pageY }; + SelectionManager.Views().forEach(docView => docView.CollectionFreeFormView?.dragStarting(false, false)); }; + _lock: any; onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => { const first = SelectionManager.Views()[0]; const effectiveAcl = GetEffectiveAcl(first.rootDoc); if (!(effectiveAcl == AclAdmin || effectiveAcl == AclEdit || effectiveAcl == AclAugment)) return false; if (!first) return false; - let thisPt = { x: e.clientX - this._offX, y: e.clientY - this._offY }; + let thisPt = { x: e.clientX - this._offset.x, y: e.clientY - this._offset.y }; var fixedAspect = Doc.NativeAspect(first.layoutDoc); + const dragHdl = this._resizeHdlId.split(' ')[0].replace('documentDecorations-', '').replace('Resizer', ''); - const resizeHdl = this._resizeHdlId.split(' ')[0]; - if (fixedAspect && (resizeHdl === 'documentDecorations-bottomRightResizer' || resizeHdl === 'documentDecorations-topLeftResizer')) { + // do snapping of drag point + if (fixedAspect && (dragHdl === 'bottomRight' || dragHdl === 'topLeft')) { // need to generalize for bl and tr drag handles const project = (p: number[], a: number[], b: number[]) => { const atob = [b[0] - a[0], b[1] - a[1]]; @@ -513,173 +505,124 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P return [a[0] + atob[0] * t, a[1] + atob[1] * t]; }; const tl = first.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - const drag = project([e.clientX + this._offX, e.clientY + this._offY], tl, [tl[0] + fixedAspect, tl[1] + 1]); + const drag = project([e.clientX + this._offset.x, e.clientY + this._offset.y], tl, [tl[0] + fixedAspect, tl[1] + 1]); thisPt = DragManager.snapDragAspect(drag, fixedAspect); } else { - thisPt = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY); + thisPt = DragManager.snapDrag(e, -this._offset.x, -this._offset.y, this._offset.x, this._offset.y); } - move[0] = thisPt.x - this._snapX; - move[1] = thisPt.y - this._snapY; - this._snapX = thisPt.x; - this._snapY = thisPt.y; - let dragBottom = false, - dragRight = false, - dragBotRight = false, - dragTop = false; - let dXin = 0, - dYin = 0, - dWin = 0, - dHin = 0; - switch (this._resizeHdlId.split(' ')[0]) { - case '': - break; - case 'documentDecorations-topLeftResizer': - dXin = -1; - dYin = -1; - dWin = -move[0]; - dHin = -move[1]; - break; - case 'documentDecorations-topRightResizer': - dWin = move[0]; - dYin = -1; - dHin = -move[1]; - break; - case 'documentDecorations-topResizer': - dYin = -1; - dHin = -move[1]; - dragTop = true; - break; - case 'documentDecorations-bottomLeftResizer': - dXin = -1; - dWin = -move[0]; - dHin = move[1]; - break; - case 'documentDecorations-bottomRightResizer': - dWin = move[0]; - dHin = move[1]; - dragBotRight = true; - break; - case 'documentDecorations-bottomResizer': - dHin = move[1]; - dragBottom = true; - break; - case 'documentDecorations-leftResizer': - dXin = -1; - dWin = -move[0]; - break; - case 'documentDecorations-rightResizer': - dWin = move[0]; - dragRight = true; - break; - } + const { scale, refPt } = this.getResizeVals(thisPt, dragHdl); + // resize selected docs + !this._lock && runInAction(async () => { + this._lock = true; + this._snapPt = thisPt; + e.ctrlKey && (SelectionManager.Views().forEach(docView => !Doc.NativeHeight(docView.props.Document) && docView.toggleNativeDimensions())); + const fixedAspect = SelectionManager.Docs().some(this.hasFixedAspect); + SelectionManager.Views().forEach(docView => + this.resizeView(docView, refPt, scale.x === 1 && fixedAspect ? scale.y : scale.x, + scale.x !== 1 && fixedAspect ? scale.x : scale.y, { dragHdl, ctrlKey:e.ctrlKey })); // prettier-ignore + await new Promise(res => setTimeout(() => res(this._lock = undefined))); + }); // prettier-ignore - const isGroup = first.rootDoc._isGroup ? first.rootDoc : undefined; - const scaleViews = isGroup ? DocListCast(isGroup.data).map(doc => DocumentManager.Instance.getFirstDocumentView(doc)!) : SelectionManager.Views(); - const aggBounds = aggregateBounds(scaleViews.map(view => view.rootDoc) as any, 0, 0); - const refWidth = aggBounds.r - aggBounds.x; - const refHeight = aggBounds.b - aggBounds.y; - const scaleRefPt = first.props - .ScreenToLocalTransform() - .inverse() - .transformPoint( - NumCast(isGroup?._xPadding) + (dXin ? refWidth : 0), // - NumCast(isGroup?._yPadding) + (dYin ? refHeight : 0) - ); - scaleViews.forEach( - action((docView: DocumentView) => { - if (e.ctrlKey && !Doc.NativeHeight(docView.props.Document)) docView.toggleNativeDimensions(); - if (dXin !== 0 || dYin !== 0 || dWin !== 0 || dHin !== 0) { - const doc = docView.rootDoc; - const refCent = docView.props.ScreenToLocalTransform().transformPoint(scaleRefPt[0], scaleRefPt[1]); - - if (doc.nativeHeightUnfrozen && !NumCast(doc.nativeHeight) && doc._nativeWidth !== undefined) { - doc._nativeHeight = (NumCast(doc._height) / NumCast(doc._width, 1)) * docView.nativeWidth; - } - const nwidth = docView.nativeWidth; - const nheight = docView.nativeHeight; - const docwidth = NumCast(doc._width); - let docheight = (hgt => (!hgt || isNaN(hgt) ? 20 : hgt))(NumCast(doc._height) || (nheight / nwidth) * docwidth); - let dW = docwidth * (dWin / refWidth); - let dH = docheight * (dHin / refHeight); - const scale = docView.props.ScreenToLocalTransform().Scale; - const modifyNativeDim = (e.ctrlKey && doc.nativeDimModifiable) || (doc.layout_forceReflow && !dragBottom && !dragTop) || (doc.nativeHeightUnfrozen && (dragBottom || dragTop || e.ctrlKey)); - if (nwidth && nheight) { - if (nwidth / nheight !== docwidth / docheight && !dragBottom && !dragTop) { - docheight = (nheight / nwidth) * docwidth; - } - if (modifyNativeDim && !dragBottom && !dragTop) { - // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction - if (Math.abs(dW) > Math.abs(dH)) dH = (dW * nheight) / nwidth; - else dW = (dH * nwidth) / nheight; - } - } - let actualdW = Math.max(docwidth + dW * scale, 20); - let actualdH = Math.max(docheight + dH * scale, 20); - let dX = !dWin ? 0 : (scale * refCent[0] * -dWin) / refWidth; - let dY = !dHin ? 0 : (scale * refCent[1] * -dHin) / refHeight; - const preserveNativeDim = !doc._nativeHeightUnfrozen && !doc._nativeDimModifiable; - const fixedAspect = nwidth && nheight && (!doc._layout_fitWidth || preserveNativeDim || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable); - if (fixedAspect) { - if ((Math.abs(dW) > Math.abs(dH) && ((!dragBottom && !dragTop) || !modifyNativeDim)) || dragRight) { - if (dragRight && modifyNativeDim) { - if (Doc.NativeWidth(doc)) { - doc._nativeWidth = (actualdW / (docwidth || 1)) * Doc.NativeWidth(doc); - } - } else { - if (!doc._layout_fitWidth || preserveNativeDim) { - actualdH = (nheight / nwidth) * actualdW; - dYin && (dY = -dW * scale * (nheight / nwidth)); - doc._height = actualdH; - } else if (!modifyNativeDim || dragBotRight) { - doc._height = actualdH; - } - } - doc._width = actualdW; - } else { - if ((dragBottom || dragTop) && (modifyNativeDim || (docView.layoutDoc.nativeHeightUnfrozen && docView.layoutDoc._layout_fitWidth))) { - // frozen web pages, PDFs, and some RTFS have frozen nativewidth/height. But they are marked to allow their nativeHeight - // to be explicitly modified with fitWidth and vertical resizing. (ie, with fitWidth they can't grow horizontally to match - // a vertical resize so it makes more sense to change their nativeheight even if the ctrl key isn't used) - doc._nativeHeight = (actualdH / (docheight || 1)) * Doc.NativeHeight(doc); - doc._layout_autoHeight = false; - } else { - if (!doc._layout_fitWidth || preserveNativeDim) { - actualdW = (nwidth / nheight) * actualdH; - dXin && (dX = -dH * scale * (nwidth / nheight)); - doc._width = actualdW; - } else if (!modifyNativeDim || dragBotRight) { - doc._width = actualdW; - } - } - if (!modifyNativeDim) { - actualdH = (nheight / nwidth) * NumCast(doc._width); //, actualdH); - } - doc._height = actualdH; - } - } else { - const rotCtr = [docwidth / 2, docheight / 2]; - const tlRotated = Utils.rotPt(-rotCtr[0], -rotCtr[1], (NumCast(doc._rotation) / 180) * Math.PI); - - const maxHeight = doc.nativeHeightUnfrozen || !nheight ? 0 : Math.max(nheight, NumCast(doc.scrollHeight, NumCast(doc[docView.LayoutFieldKey + '_scrollHeight']))) * docView.NativeDimScaling(); - dH && (doc._height = actualdH > maxHeight && maxHeight ? maxHeight : actualdH); - dW && (doc._width = actualdW); - dH && (doc._layout_autoHeight = false); - - const rotCtr2 = [NumCast(doc._width) / 2, NumCast(doc._height) / 2]; - const tlRotated2 = Utils.rotPt(-rotCtr2[0], -rotCtr2[1], (NumCast(doc._rotation) / 180) * Math.PI); - doc.x = NumCast(doc.x) + tlRotated.x + rotCtr[0] - (tlRotated2.x + rotCtr2[0]); // doc shifts by amount topleft moves because rotation is about center of doc - doc.y = NumCast(doc.y) + tlRotated.y + rotCtr[1] - (tlRotated2.y + rotCtr2[1]); - } - doc.x = NumCast(doc.x) + dX; - doc.y = NumCast(doc.y) + dY; - doc._layout_modificationDate = new DateField(); + return false; + }; + + // + // determines how much to resize, and determines the resize reference point + // + getResizeVals = (thisPt: { x: number; y: number }, dragHdl: string) => { + const [w, h] = [this.Bounds.r - this.Bounds.x, this.Bounds.b - this.Bounds.y]; + const [moveX, moveY] = [thisPt.x - this._snapPt.x, thisPt.y - this._snapPt.y]; + switch (dragHdl) { + case 'topLeft': return { scale: { x: 1 - moveX / w, y: 1 -moveY / h }, refPt: [this.Bounds.r, this.Bounds.b] }; + case 'topRight': return { scale: { x: 1 + moveX / w, y: 1 -moveY / h }, refPt: [this.Bounds.x, this.Bounds.b] }; + case 'top': return { scale: { x: 1, y: 1 -moveY / h }, refPt: [this.Bounds.x, this.Bounds.b] }; + case 'left': return { scale: { x: 1 - moveX / w, y: 1 }, refPt: [this.Bounds.r, this.Bounds.y] }; + case 'bottomLeft': return { scale: { x: 1 - moveX / w, y: 1 + moveY / h }, refPt: [this.Bounds.r, this.Bounds.y] }; + case 'right': return { scale: { x: 1 + moveX / w, y: 1 }, refPt: [this.Bounds.x, this.Bounds.y] }; + case 'bottomRight':return { scale: { x: 1 + moveX / w, y: 1 + moveY / h }, refPt: [this.Bounds.x, this.Bounds.y] }; + case 'bottom': return { scale: { x: 1, y: 1 + moveY / h }, refPt: [this.Bounds.x, this.Bounds.y] }; + default: return { scale: { x: 1, y: 1 }, refPt: [this.Bounds.x, this.Bounds.y] }; + } // prettier-ignore + }; + + // + // determines if anything being dragged directly or via a group has a fixed aspect ratio (in which case we resize uniformly) + // + hasFixedAspect = (doc: Doc): boolean => (doc.isGroup ? DocListCast(doc.data).some(this.hasFixedAspect) : !BoolCast(doc.layout_nativeDimEditable)); + + // + // resize a single DocumentView about the specified reference point, possibly setting/updating the native dimensions of the Doc + // + resizeView = (docView: DocumentView, refPt: number[], scaleX: number, scaleY: number, opts: { dragHdl: string; ctrlKey: boolean }) => { + const doc = docView.rootDoc; + if (doc.isGroup) { + DocListCast(doc.data) + .map(member => DocumentManager.Instance.getDocumentView(member, docView)!) + .forEach(member => this.resizeView(member, refPt, scaleX, scaleY, opts)); + doc.xPadding = NumCast(doc.xPadding) * scaleX; + doc.yPadding = NumCast(doc.yPadding) * scaleY; + } else { + const doc = docView.rootDoc; + const refCent = docView.props.ScreenToLocalTransform().transformPoint(refPt[0], refPt[1]); // fixed reference point for resize (ie, a point that doesn't move) + const [nwidth, nheight] = [docView.nativeWidth, docView.nativeHeight]; + const [initWidth, initHeight] = [NumCast(doc._width, 1), NumCast(doc._height)]; + + const modifyNativeDim = + (opts.ctrlKey && doc.layout_nativeDimEditable) || // e.g., PDF or web page + (doc.layout_reflowHorizontal && opts.dragHdl !== 'bottom' && opts.dragHdl !== 'top') || // eg rtf or some web pages + (doc.layout_reflowVertical && (opts.dragHdl === 'bottom' || opts.dragHdl === 'top' || opts.ctrlKey)); // eg rtf, web, pdf + if (nwidth && nheight && !modifyNativeDim) { + // eg., dragging right resizer on PDF -- enforce native dimensions because not expliclty overridden with ctrl or bottom resize drag + scaleX === 1 ? (scaleX = scaleY) : (scaleY = scaleX); + } + + if (['right', 'left'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeWidth(doc)) { + const setData = Doc.NativeWidth(Doc.GetProto(doc)) === doc.nativeWidth; + doc.nativeWidth = scaleX * Doc.NativeWidth(doc); + if (setData) Doc.SetNativeWidth(Doc.GetProto(doc), NumCast(doc.nativeWidth)); + if (doc.layout_reflowVertical && !NumCast(doc.nativeHeight)) { + doc._nativeHeight = (initHeight / initWidth) * nwidth; // initializes the nativeHeight for a PDF } - const val = this._dragHeights.get(docView.layoutDoc); - if (val) this._dragHeights.set(docView.layoutDoc, { start: val.start, lowest: Math.min(val.lowest, NumCast(docView.layoutDoc._height)) }); - }) + } + if (['bottom', 'top'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeHeight(doc)) { + const setData = Doc.NativeHeight(Doc.GetProto(doc)) === doc.nativeHeight; + doc._nativeHeight = scaleY * Doc.NativeHeight(doc); + if (setData) Doc.SetNativeHeight(Doc.GetProto(doc), NumCast(doc._nativeHeight)); + } + + doc._width = NumCast(doc._width) * scaleX; + doc._height = NumCast(doc._height) * scaleY; + const { deltaX, deltaY } = this.realignRefPt(doc, refCent, initWidth, initHeight); + doc.x = NumCast(doc.x) + deltaX; + doc.y = NumCast(doc.y) + deltaY; + + doc._layout_modificationDate = new DateField(); + scaleY !== 1 && (doc._layout_autoHeight = undefined); + } + }; + + // This realigns the doc's resize reference point with where it was before resizing it. + // This is needed, because the transformation for doc's with a rotation is screwy: + // the top left of the doc is the 'origin', but the rotation happens about the center of the Doc. + // So resizing a rotated doc will cause it to shift -- this counteracts that shift by determine how + // the reference points shifted, and returning a translation to restore the reference point. + realignRefPt = (doc: Doc, refCent: number[], initWidth: number, initHeight: number) => { + const refCentPct = [refCent[0] / initWidth, refCent[1] / initHeight]; + const rotRefStart = Utils.rotPt( + refCent[0] - initWidth / 2, // rotate reference pointe before scaling + refCent[1] - initHeight / 2, + (NumCast(doc._rotation) / 180) * Math.PI ); - return false; + const rotRefEnd = Utils.rotPt( + refCentPct[0] * NumCast(doc._width) - NumCast(doc._width) / 2, // rotate reference point after scaling + refCentPct[1] * NumCast(doc._height) - NumCast(doc._height) / 2, + (NumCast(doc._rotation) / 180) * Math.PI + ); + return { + deltaX: rotRefStart.x + initWidth / 2 - (rotRefEnd.x + NumCast(doc._width) / 2), // + deltaY: rotRefStart.y + initHeight / 2 - (rotRefEnd.y + NumCast(doc._height) / 2), + }; }; @action @@ -691,10 +634,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P SnappingManager.clearSnapLines(); // detect layout_autoHeight gesture and apply - SelectionManager.Views() - .map(docView => ({ doc: docView.layoutDoc, hgts: this._dragHeights.get(docView.layoutDoc) })) - .filter(pair => pair.hgts && pair.hgts.lowest < pair.hgts.start && pair.hgts.lowest <= 20) - .forEach(pair => (pair.doc._layout_autoHeight = true)); + SelectionManager.Docs().forEach(doc => NumCast(doc._height) < 20 && (doc._layout_autoHeight = true)); //need to change points for resize, or else rotation/control points will fail. this._inkDragDocs .map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx index 0d7f7ebd8..e5141b7f4 100644 --- a/src/client/views/InkControlPtHandles.tsx +++ b/src/client/views/InkControlPtHandles.tsx @@ -12,6 +12,7 @@ import { UndoManager } from '../util/UndoManager'; import { Colors } from './global/globalEnums'; import { InkingStroke } from './InkingStroke'; import { InkStrokeProperties } from './InkStrokeProperties'; +import { SnappingManager } from '../util/SnappingManager'; export interface InkControlProps { inkDoc: Doc; @@ -190,6 +191,7 @@ export class InkEndPtHandles extends React.Component { @action dragRotate = (e: React.PointerEvent, pt1: () => { X: number; Y: number }, pt2: () => { X: number; Y: number }) => { + SnappingManager.SetIsDragging(true); setupMoveUpEvents( this, e, @@ -211,6 +213,7 @@ export class InkEndPtHandles extends React.Component { return false; }), action(() => { + SnappingManager.SetIsDragging(false); this.props.inkView.controlUndo?.end(); this.props.inkView.controlUndo = undefined; UndoManager.FilterBatches(['stroke', 'x', 'y', 'width', 'height']); @@ -237,8 +240,8 @@ export class InkEndPtHandles extends React.Component { ); return ( - {hdl('start', this.props.startPt(), (e: React.PointerEvent) => this.dragRotate(e, this.props.startPt, this.props.endPt))} - {hdl('end', this.props.endPt(), (e: React.PointerEvent) => this.dragRotate(e, this.props.endPt, this.props.startPt))} + {hdl('start', this.props.startPt(), e => this.dragRotate(e, this.props.startPt, this.props.endPt))} + {hdl('end', this.props.endPt(), e => this.dragRotate(e, this.props.endPt, this.props.startPt))} ); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index a6f0b9e84..5bed0f923 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -252,6 +252,7 @@ export class MainView extends React.Component { fa.faShare, fa.faTaxi, fa.faDownload, + fa.faPallet, fa.faExpandArrowsAlt, fa.faAmbulance, fa.faLayerGroup, diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 81453c0b8..c2586fb4b 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -295,7 +295,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { const aspect = Doc.NativeAspect(layout, undefined, true); const width = () => this.lookupPixels(layout); const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); - const docwidth = () => (layout._layout_forceReflow ? width() : Math.min(height() * aspect, width())); + const docwidth = () => (layout._layout_reflowHorizontal ? width() : Math.min(height() * aspect, width())); const docheight = () => Math.min(docwidth() / aspect, height()); const dxf = () => this.lookupIndividualTransform(layout) diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 04cfc5456..249c3551b 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -292,7 +292,7 @@ export class CollectionMultirowView extends CollectionSubView() { const height = () => this.lookupPixels(layout); const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); const docheight = () => Math.min(width() / aspect, height()); - const docwidth = () => (layout._layout_forceReflow ? width() : Math.min(width(), docheight() * aspect)); + const docwidth = () => (layout._layout_reflowHorizontal ? width() : Math.min(width(), docheight() * aspect)); const dxf = () => this.lookupIndividualTransform(layout) .translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin) - (height() - docheight()) / 2) diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index c690b8623..3af523d73 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -181,16 +181,22 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh map.get(attr)?.setDoc?.(); }); -type attrname = 'noAutoLink' | 'dictation' | 'bold' | 'italics' | 'underline' | 'left' | 'center' | 'right' | 'bullet' | 'decimal'; +type attrname = 'noAutoLink' | 'dictation' | 'bold' | 'italics' | 'underline' | 'left' | 'center' | 'right' | 'vcent' | 'bullet' | 'decimal'; type attrfuncs = [attrname, { checkResult: () => boolean; toggle: () => any }]; ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?: boolean) { const textView = RichTextMenu.Instance?.TextView; const editorView = textView?.EditorView; // prettier-ignore - const alignments:attrfuncs[] = (['left','right','center'] as ("left"|"center"|"right")[]).map((where) => - [ where, { checkResult: () =>(editorView ? (RichTextMenu.Instance.textAlign ===where): (Doc.UserDoc().textAlign ===where) ? true:false), - toggle: () => (editorView?.state ? RichTextMenu.Instance.align(editorView, editorView.dispatch, where):(Doc.UserDoc().textAlign = where))}]); + const alignments:attrfuncs[] = (['left','right','center','vcent'] as ("left"|"center"|"right"|"vcent")[]).map((where) => + [ where, { checkResult: () =>(editorView ? (where === 'vcent' ? SelectionManager.Docs().some(doc => doc.layout_centered): + (RichTextMenu.Instance.textAlign === where)): + where === 'vcent' ? BoolCast(Doc.UserDoc().layout_centered): + (Doc.UserDoc().textAlign ===where) ? true:false), + toggle: () => (editorView?.state ? (where === 'vcent' ? SelectionManager.Docs().forEach(doc => doc.layout_centered = !doc.layout_centered): + RichTextMenu.Instance.align(editorView, editorView.dispatch, where)): + where === 'vcent' ? Doc.UserDoc().layout_centered = !Doc.UserDoc().layout_centered: + (Doc.UserDoc().textAlign = where))}]); // prettier-ignore // prettier-ignore const listings:attrfuncs[] = (['bullet','decimal'] as attrname[]).map(list => [ list, { checkResult: () => (editorView ? RichTextMenu.Instance.getActiveListStyle() === list:false), diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index a05d6c904..582a5518a 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -62,7 +62,7 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent this.Y; // prettier-ignore w_Z = () => this.Z; // prettier-ignore w_ZIndex = () => this.ZIndex ?? NumCast(this.props.Document.zIndex); // prettier-ignore - w_Rot = () => this.Rotation ?? NumCast(this.props.Document._rotation); // prettier-ignore + w_Rotation = () => this.Rotation ?? NumCast(this.props.Document._rotation); // prettier-ignore w_Opacity = () => this.Opacity; // prettier-ignore w_BackgroundColor = () => this.BackgroundColor ?? Cast(this.props.Document._backgroundColor, 'string', null); // prettier-ignore w_Color = () => this.Color ?? Cast(this.props.Document._color, 'string', null); // prettier-ignore diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 299494c83..b3f813eda 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -115,8 +115,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { layoutDoc: this.layoutDoc, records: this.records, axes: this.axes, - height: (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9, - width: this.props.PanelWidth() * 0.9, + height: (this.props.PanelHeight() * (this.props.NativeDimScaling?.() || 1) - 32) /* height of 'change view' button */ * 0.9, + width: this.props.PanelWidth() * (this.props.NativeDimScaling?.() || 1) * 0.9, margin: { top: 10, right: 25, bottom: 75, left: 45 }, }; if (!this.records.length) return 'no data/visualization'; @@ -133,6 +133,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { }; render() { + const scale = this.props.NativeDimScaling?.() || 1; + return !this.records.length ? ( // displays how to get data into the DataVizBox if its empty
To create a DataViz box, either import / drag a CSV file into your canvas or copy a data table and use the command 'ctrl + p' to bring the data table to your canvas.
@@ -141,6 +143,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { className="dataViz" style={{ pointerEvents: this.props.isContentActive() === true ? 'all' : 'none', + width: `${100 / scale}%`, + height: `${100 / scale}%`, + transform: `scale(${scale})`, + position: 'absolute', }} onWheel={e => e.stopPropagation()} ref={r => diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d1caf0acf..e3d6c3fdf 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1495,7 +1495,7 @@ export class DocumentView extends React.Component { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth(); } @computed get panelHeight() { - if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.nativeHeightUnfrozen)) { + if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.layout_reflowVertical)) { return Math.min(this.props.PanelHeight(), this.effectiveNativeHeight * this.nativeScaling); } return this.props.PanelHeight(); @@ -1507,7 +1507,7 @@ export class DocumentView extends React.Component { return this.effectiveNativeWidth && this.effectiveNativeHeight && Math.abs(this.Xshift) < 0.001 && - (!this.layoutDoc.nativeHeightUnfrozen || (!this.layout_fitWidth && this.effectiveNativeHeight * this.nativeScaling <= this.props.PanelHeight())) + (!this.layoutDoc.layout_reflowVertical || (!this.layout_fitWidth && this.effectiveNativeHeight * this.nativeScaling <= this.props.PanelHeight())) ? Math.max(0, (this.props.PanelHeight() - this.effectiveNativeHeight * this.nativeScaling) / 2) : 0; } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index bde1d5fa4..185c6553a 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -347,7 +347,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']); const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; - const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth + PDFBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth; + const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth + PDFBox.sidebarResizerWidth : 0) + NumCast(this.layoutDoc._width)) / NumCast(this.layoutDoc._width); const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); if (preview) { this._previewNativeWidth = nativeWidth * sideratio; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index a452b1cdd..d9ea48c3b 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -707,10 +707,10 @@ export class WebBox extends ViewBoxAnnotatableComponent { - const nw = !this.layoutDoc.layout_forceReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.NativeDimScaling?.() || 1); - this.layoutDoc.layout_forceReflow = !nw; + const nw = !this.layoutDoc.layout_reflowHorizontal ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.NativeDimScaling?.() || 1); + this.layoutDoc.layout_reflowHorizontal = !nw; if (nw) { Doc.SetInPlace(this.layoutDoc, this.fieldKey + '_nativeWidth', nw, true); } @@ -872,13 +872,13 @@ export class WebBox extends ViewBoxAnnotatableComponent { var nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']); if (!nativeWidth) { - const defaultNativeWidth = this.rootDoc[this.fieldKey] instanceof WebField ? 850 : NumCast(this.Document._width); + const defaultNativeWidth = NumCast(this.rootDoc.nativeWidth, this.rootDoc[this.fieldKey] instanceof WebField ? 850 : NumCast(this.Document._width)); Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || defaultNativeWidth); Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || (NumCast(this.Document._height) / NumCast(this.Document._width)) * defaultNativeWidth); nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']); } const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; - const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth + WebBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth; + const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth + WebBox.sidebarResizerWidth : 0) + NumCast(this.layoutDoc.width)) / NumCast(this.layoutDoc.width); const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); if (preview) { this._previewNativeWidth = nativeWidth * sideratio; @@ -890,6 +890,7 @@ export class WebBox extends ViewBoxAnnotatableComponent e.stopPropagation()} style={{ - width: !this.layoutDoc.layout_forceReflow ? NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']) || `100%` : '100%', + width: !this.layoutDoc.layout_reflowHorizontal ? NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']) || `100%` : '100%', transform: `scale(${this.zoomScaling()}) translate(${-NumCast(this.layoutDoc.freeform_panX)}px, ${-NumCast(this.layoutDoc.freeform_panY)}px)`, }}> {this._hackHide ? null : this.urlContent} diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 9ab3189a6..a80c1e030 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -704,14 +704,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + const defaultSidebar = 250; const prevWidth = 1 - this.sidebarWidth() / Number(getComputedStyle(this._ref.current!).width.replace('px', '')); if (preview) this._showSidebar = true; else { this.layoutDoc[this.SidebarKey + '_freeform_scale_max'] = 1; - this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? '50%' : '0%') !== '0%'; + this.layoutDoc._layout_showSidebar = + (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(defaultSidebar / (NumCast(this.layoutDoc._width) + defaultSidebar)) * 100}%` : '0%') !== '0%'; } - this.layoutDoc._width = !preview && this.SidebarShown ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) * prevWidth); + this.layoutDoc._width = !preview && this.SidebarShown ? NumCast(this.layoutDoc._width) + defaultSidebar : Math.max(20, NumCast(this.layoutDoc._width) * prevWidth); }; sidebarDown = (e: React.PointerEvent) => { const batch = UndoManager.StartBatch('toggle sidebar'); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 6dece87b5..e91fcd858 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1295,17 +1295,11 @@ export namespace Doc { layoutDoc._freeform_scale = NumCast(layoutDoc._freeform_scale, 1) * contentScale; layoutDoc._nativeWidth = undefined; layoutDoc._nativeHeight = undefined; - layoutDoc._layout_forceReflow = undefined; - layoutDoc._nativeHeightUnfrozen = undefined; - layoutDoc._nativeDimModifiable = undefined; } else { layoutDoc._layout_autoHeight = false; if (!Doc.NativeWidth(layoutDoc)) { layoutDoc._nativeWidth = NumCast(layoutDoc._width, panelWidth); layoutDoc._nativeHeight = NumCast(layoutDoc._height, panelHeight); - layoutDoc._layout_forceReflow = true; - layoutDoc._nativeHeightUnfrozen = true; - layoutDoc._nativeDimModifiable = true; } } }); -- cgit v1.2.3-70-g09d2 From e4a3b962f8de00f5bc0463bed886d9f8f526ff89 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 Nov 2023 09:09:50 -0500 Subject: fixes for selecting/moving docs that are rotated. --- src/client/util/DragManager.ts | 16 ++- src/client/views/DocumentDecorations.tsx | 23 ++++- .../collectionFreeForm/CollectionFreeFormView.tsx | 26 ++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 3 +- src/client/views/nodes/WebBoxRenderer.js | 113 +++++++++++---------- 5 files changed, 104 insertions(+), 77 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index f928a1bf9..6e4de252d 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -8,6 +8,7 @@ import { ScriptCast, StrCast } from '../../fields/Types'; import { emptyFunction, Utils } from '../../Utils'; import { Docs, DocUtils } from '../documents/Documents'; import * as globalCssVariables from '../views/global/globalCssVariables.scss'; +import { CollectionFreeFormDocumentView } from '../views/nodes/CollectionFreeFormDocumentView'; import { DocumentView } from '../views/nodes/DocumentView'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; @@ -360,11 +361,18 @@ export namespace DragManager { const docsToDrag = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnchorAnnoDragData ? [dragData.dragDocument] : []; const dragElements = eles.map(ele => { // bcz: very hacky -- if dragged element is a freeForm view with a rotation, then extract the rotation in order to apply it to the dragged element - let useDim = false; // if doc is rotated by freeformview, then the dragged elements width and height won't reflect the unrotated dimensions, so we need to rely on the element knowing its own width/height. \ + // bcz: used to be false, but that made dragging collection w/ native dim's not work... + let useDim = true; // if doc is rotated by freeformview, then the dragged elements width and height won't reflect the unrotated dimensions, so we need to rely on the element knowing its own width/height. \ // if the parent isn't a freeform view, then the element's width and height are presumed to match the acutal doc's dimensions (eg, dragging from import sidebar menu) - if (ele?.parentElement?.parentElement?.parentElement?.className === 'collectionFreeFormDocumentView-container') { - ele = ele.parentElement.parentElement.parentElement; - rot.push(Number(ele.style.transform.replace(/.*rotate\(([-0-9.e]*)deg\).*/, '$1') || 0)); + let rotation: number | undefined; + for (let parEle: HTMLElement | null | undefined = ele.parentElement; parEle; parEle = parEle?.parentElement) { + if (parEle.className === CollectionFreeFormDocumentView.CollectionFreeFormDocViewClassName) { + rotation = (rotation ?? 0) + Number(parEle.style.transform.replace(/.*rotate\(([-0-9.e]*)deg\).*/, '$1') || 0); + } + parEle = parEle.parentElement; + } + if (rotation !== undefined) { + rot.push(rotation); } else { useDim = true; rot.push(0); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 77554bd51..6663c5ee8 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { IconButton } from 'browndash-components'; -import { action, computed, observable, reaction, runInAction } from 'mobx'; +import { action, computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { FaUndo } from 'react-icons/fa'; import { DateField } from '../../fields/DateField'; @@ -65,7 +65,17 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P super(props); DocumentDecorations.Instance = this; document.addEventListener('pointermove', // show decorations whenever pointer moves outside of selection bounds. - action(e => (this._showNothing = !(this.Bounds.x !== Number.MAX_VALUE && (this.Bounds.x > e.clientX + this._resizeBorderWidth / 2 || this.Bounds.r < e.clientX - this._resizeBorderWidth / 2 || this.Bounds.y > e.clientY + this._resizeBorderWidth / 2 || this.Bounds.b < e.clientY - this._resizeBorderWidth / 2))))); // prettier-ignore + action(e => { + const center = {x: (this.Bounds.x+this.Bounds.r)/2, y: (this.Bounds.y+this.Bounds.b)/2}; + const {x,y} = Utils.rotPt(e.clientX - center.x, + e.clientY - center.y, + -NumCast(SelectionManager.Docs().lastElement()?.rotation)/180*Math.PI); + (this._showNothing = !(this.Bounds.x !== Number.MAX_VALUE && // + (this.Bounds.x > center.x+x + this._resizeBorderWidth / 2 || + this.Bounds.r < center.x+x - this._resizeBorderWidth / 2 || + this.Bounds.y > center.y+y + this._resizeBorderWidth / 2 || + this.Bounds.b < center.y+y - this._resizeBorderWidth / 2))); + })); // prettier-ignore } @computed get ClippedBounds() { @@ -524,7 +534,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P (doc.layout_reflowVertical && (opts.dragHdl === 'bottom' || opts.dragHdl === 'top' || opts.ctrlKey)); // eg rtf, web, pdf if (nwidth && nheight && !modifyNativeDim) { // eg., dragging right resizer on PDF -- enforce native dimensions because not expliclty overridden with ctrl or bottom resize drag - scale.x === 1 ? (scale.x = scale.y) : (scale.x = scale.x); + scale.x === 1 ? (scale.x = scale.y) : (scale.y = scale.x); } if (['right', 'left'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeWidth(doc)) { @@ -688,7 +698,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const bounds = this.ClippedBounds; const useLock = bounds.r - bounds.x > 135 && seldocview.CollectionFreeFormDocumentView; const useRotation = !hideResizers && seldocview.rootDoc.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate? - const rotation = SelectionManager.Views().length == 1 ? NumCast(seldocview.rootDoc._rotation) : 0; + const rotation = SelectionManager.Views().length == 1 ? seldocview.docViewPath.reduce((rot, view) => rot + NumCast(view.rootDoc._rotation), 0) : 0; // Radius constants const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView; @@ -748,6 +758,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P )}
); + const centery = hideTitle ? 0 : this._titleHeight; + const transformOrigin = `${50}% calc(50% + ${centery / 2}px)`; const freeformDoc = SelectionManager.Views().some(v => v.CollectionFreeFormDocumentView); return (
@@ -758,9 +770,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P height: bounds.b - bounds.y + this._resizeBorderWidth + 'px', left: bounds.x - this._resizeBorderWidth / 2, top: bounds.y - this._resizeBorderWidth / 2, + transformOrigin, background: SnappingManager.GetShiftKey() ? undefined : 'yellow', pointerEvents: SnappingManager.GetShiftKey() || DocumentView.Interacting ? 'none' : 'all', display: SelectionManager.Views().length <= 1 || hideDecorations ? 'none' : undefined, + transform: `rotate(${rotation}deg)`, }} onPointerDown={this.onBackgroundDown} /> @@ -770,6 +784,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P className={`documentDecorations-container ${this._showNothing ? 'showNothing' : ''}`} style={{ transform: `translate(${bounds.x - this._resizeBorderWidth / 2}px, ${bounds.y - this._resizeBorderWidth / 2 - this._titleHeight}px) rotate(${rotation}deg)`, + transformOrigin, width: bounds.r - bounds.x + this._resizeBorderWidth + 'px', height: bounds.b - bounds.y + this._resizeBorderWidth + (this._showNothing ? 0 : this._titleHeight) + 'px', }}> diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 45af1064a..75e27aa43 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -341,16 +341,17 @@ export class CollectionFreeFormView extends CollectionSubView= panX + panelWidMax / 2) panX = ranges.xrange.max + (this.props.originTopLeft ? 0 : panelWidMax / 2); else if (ranges.xrange.max <= panX - panelWidMin / 2) panX = ranges.xrange.min - (this.props.originTopLeft ? panelWidMax / 2 : panelWidMin / 2); if (ranges.yrange.min >= panY + panelHgtMax / 2) panY = ranges.yrange.max + (this.props.originTopLeft ? 0 : panelHgtMax / 2); @@ -1537,8 +1539,8 @@ export class CollectionFreeFormView extends CollectionSubView { this.dataDoc.icon = new ImageField(iconFile); - this.dataDoc['icon_nativeWidth'] = nativeWidth; - this.dataDoc['icon_nativeHeight'] = nativeHeight; + this.dataDoc.icon_nativeWidth = nativeWidth; + this.dataDoc.icon_nativeHeight = nativeHeight; } ); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 582a5518a..5fbe5d0e3 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -239,12 +239,13 @@ export class CollectionFreeFormDocumentView extends DocComponent key.startsWith('w_'))).omit; // prettier-ignore return (
{ const reader = new FileReader(); reader.readAsDataURL(binStr); reader.onloadend = function () { @@ -31,17 +31,17 @@ var ForeignHtmlRenderer = function (styleSheets) { * @returns {Promise} */ const getResourceAsBase64 = function (webUrl, inurl) { - return new Promise(function (resolve, reject) { + return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); - //const url = inurl.startsWith("/") && !inurl.startsWith("//") ? webUrl + inurl : inurl; - //const url = CorsProxy(inurl.startsWith("/") && !inurl.startsWith("//") ? webUrl + inurl : inurl);// inurl.startsWith("http") ? CorsProxy(inurl) : inurl; - var url = inurl; + // const url = inurl.startsWith("/") && !inurl.startsWith("//") ? webUrl + inurl : inurl; + // const url = CorsProxy(inurl.startsWith("/") && !inurl.startsWith("//") ? webUrl + inurl : inurl);// inurl.startsWith("http") ? CorsProxy(inurl) : inurl; + let url = inurl; if (inurl.startsWith('/static')) { url = new URL(webUrl).origin + inurl; } else if (inurl.startsWith('/') && !inurl.startsWith('//')) { url = CorsProxy(new URL(webUrl).origin + inurl); } else if (!inurl.startsWith('http') && !inurl.startsWith('//')) { - url = CorsProxy(webUrl + '/' + inurl); + url = CorsProxy(`${webUrl}/${inurl}`); } else if (inurl.startsWith('https') && !inurl.startsWith(window.location.origin)) { url = CorsProxy(inurl); } @@ -57,7 +57,7 @@ var ForeignHtmlRenderer = function (styleSheets) { resourceBase64: resBase64, }); } else if (xhr.readyState === XMLHttpRequest.DONE) { - console.log("COULDN'T FIND: " + (inurl.startsWith('/') ? webUrl + inurl : inurl)); + console.log(`COULDN'T FIND: ${inurl.startsWith('/') ? webUrl + inurl : inurl}`); resolve({ resourceUrl: '', resourceBase64: inurl, @@ -76,7 +76,7 @@ var ForeignHtmlRenderer = function (styleSheets) { */ const getMultipleResourcesAsBase64 = function (webUrl, urls) { const promises = []; - for (let i = 0; i < urls.length; i++) { + for (let i = 0; i < urls.length; i += 1) { promises.push(getResourceAsBase64(webUrl, urls[i])); } return Promise.all(promises); @@ -98,7 +98,7 @@ var ForeignHtmlRenderer = function (styleSheets) { } let val = ''; - for (let i = idx + prefixToken.length; i < str.length; i++) { + for (let i = idx + prefixToken.length; i < str.length; i += 1) { if (suffixTokens.indexOf(str[i]) !== -1) { break; } @@ -112,6 +112,15 @@ var ForeignHtmlRenderer = function (styleSheets) { }; }; + /** + * + * @param {String} str + * @returns {String} + */ + const removeQuotes = function (str) { + return str.replace(/["']/g, ''); + }; + /** * * @param {String} cssRuleStr @@ -127,13 +136,12 @@ var ForeignHtmlRenderer = function (styleSheets) { break; } searchStartIndex = url.foundAtIndex + url.value.length + 1; - if (mustEndWithQuote && url.value[url.value.length - 1] !== '"') continue; - const unquoted = removeQuotes(url.value); - if (!unquoted /* || (!unquoted.startsWith('http')&& !unquoted.startsWith("/") )*/ || unquoted === 'http://' || unquoted === 'https://') { - continue; + if (!mustEndWithQuote || url.value[url.value.length - 1] === '"') { + const unquoted = removeQuotes(url.value); + if (unquoted /* || (!unquoted.startsWith('http')&& !unquoted.startsWith("/") ) */ && unquoted !== 'http://' && unquoted !== 'https://') { + if (unquoted) urlsFound.push(unquoted); + } } - - unquoted && urlsFound.push(unquoted); } return urlsFound; @@ -151,15 +159,6 @@ var ForeignHtmlRenderer = function (styleSheets) { return getUrlsFromCssString(html, 'source=', [' ', '>', '\t'], true); }; - /** - * - * @param {String} str - * @returns {String} - */ - const removeQuotes = function (str) { - return str.replace(/["']/g, ''); - }; - const escapeRegExp = function (string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string }; @@ -172,8 +171,8 @@ var ForeignHtmlRenderer = function (styleSheets) { * * @returns {Promise} */ - const buildSvgDataUri = async function (webUrl, contentHtml, width, height, scroll, xoff) { - return new Promise(async function (resolve, reject) { + const buildSvgDataUri = async function (webUrl, inputContentHtml, width, height, scroll, xoff) { + return new Promise(async (resolve, reject) => { /* !! The problems !! * 1. CORS (not really an issue, expect perhaps for images, as this is a general security consideration to begin with) * 2. Platform won't wait for external assets to load (fonts, images, etc.) @@ -181,17 +180,19 @@ var ForeignHtmlRenderer = function (styleSheets) { // copy styles let cssStyles = ''; - let urlsFoundInCss = []; + const urlsFoundInCss = []; - for (let i = 0; i < styleSheets.length; i++) { + for (let i = 0; i < styleSheets.length; i += 1) { try { const rules = styleSheets[i].cssRules; - for (let j = 0; j < rules.length; j++) { + for (let j = 0; j < rules.length; j += 1) { const cssRuleStr = rules[j].cssText; urlsFoundInCss.push(...getUrlsFromCssString(cssRuleStr)); cssStyles += cssRuleStr; } - } catch (e) {} + } catch (e) { + /* empty */ + } } // const fetchedResourcesFromStylesheets = await getMultipleResourcesAsBase64(webUrl, urlsFoundInCss); @@ -202,15 +203,15 @@ var ForeignHtmlRenderer = function (styleSheets) { // } // } - contentHtml = contentHtml + let contentHtml = inputContentHtml .replace(/]*>/g, '') // tags have a which has a srcset field of image refs. instead of converting each, just use the default of the picture .replace(/noscript/g, 'div') .replace(/
<\/div>/g, '') // when scripting isn't available (ie, rendering web pages here),
{/* */}
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss index f803715ad..f90c19050 100644 --- a/src/client/views/nodes/VideoBox.scss +++ b/src/client/views/nodes/VideoBox.scss @@ -100,6 +100,7 @@ padding: 0 10px 0 7px; transition: opacity 0.3s; z-index: 10001; + transform-origin: top left; .timecode-controls { display: flex; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 6ebf84738..8bf2f4ce5 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -64,6 +64,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent(); private _mainCont: React.RefObject = React.createRef(); // outermost div private _annotationLayer: React.RefObject = React.createRef(); private _playRegionTimer: any = null; // timeout for playback @@ -71,7 +72,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent(); @observable _screenCapture = false; @observable _clicking = false; // used for transition between showing/hiding timeline @@ -867,7 +867,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - this._marqueeing = [e.clientX, e.clientY]; + this._marqueeref.current?.onInitiateSelection([e.clientX, e.clientY]); return true; }), returnFalse, @@ -881,7 +881,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { - this._marqueeing = undefined; + this._marqueeref.current?.onTerminateSelection(); this.props.select(true); }; @@ -912,7 +912,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent ((this.props.NativeDimScaling?.() || 1) * this.heightPercent) / 100; marqueeOffset = () => [((this.panelWidth() / 2) * (1 - this.heightPercent / 100)) / (this.heightPercent / 100), 0]; timelineDocFilter = () => [`_isTimelineLabel:true,${Utils.noRecursionHack}:x`]; @@ -937,8 +936,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent StrListCast(this.dataDoc[this.fieldKey + '_thumbnails']); // renders CollectionStackedTimeline @computed get renderTimeline() { return ( @@ -963,7 +962,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent StrListCast(this.dataDoc[this.fieldKey + '_thumbnails'])} + thumbnails={this.thumbnails} renderDepth={this.props.renderDepth + 1} startTag={'_timecodeToShow' /* videoStart */} endTag={'_timecodeToHide' /* videoEnd */} @@ -1095,13 +1094,15 @@ export class VideoBox extends ViewBoxAnnotatableComponent
{this.annotationLayer} - {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this._annotationLayer.current ? null : ( ) => void); private _mainCont: React.RefObject = React.createRef(); private _outerRef: React.RefObject = React.createRef(); + private _marqueeref = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; private _annotationLayer: React.RefObject = React.createRef(); private _keyInput = React.createRef(); @@ -66,10 +67,15 @@ export class WebBox extends ViewBoxAnnotatableComponent; @observable private _marqueeing: number[] | undefined; - @observable private _isAnnotating = false; - @observable private _iframeClick: HTMLIFrameElement | undefined = undefined; + get marqueeing() { + return this._marqueeing; + } + set marqueeing(val) { + val && this._marqueeref.current?.onInitiateSelection(val); + !val && this._marqueeref.current?.onTerminateSelection(); + this._marqueeing = val; + } @observable private _iframe: HTMLIFrameElement | null = null; @observable private _savedAnnotations = new ObservableMap(); @observable private _scrollHeight = NumCast(this.layoutDoc.scrollHeight); @@ -245,6 +251,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { if (this._mainCont.current && selRange) { + if (this.rootDoc[this.props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this.props.DocumentView!().screenToLocalTransform().RotateDeg)}deg)`; const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { const rect = clientRects.item(i); @@ -261,12 +268,13 @@ export class WebBox extends ViewBoxAnnotatableComponent { - const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); + e.stopPropagation(); + const sel = window.getSelection(); + this._textAnnotationCreator = undefined; + if (sel?.empty) sel.empty(); // Chrome + else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox + // bcz: NEED TO unrotate e.clientX and e.clientY const word = getWordAtPoint(e.target, e.clientX, e.clientY); this._setPreviewCursor?.(e.clientX, e.clientY, false, true, this.rootDoc); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - e.button !== 2 && (this._marqueeing = [e.clientX, e.clientY]); - if (word || (e.target as any)?.className?.includes('rangeslider') || (e.target as any)?.onclick || (e.target as any)?.parentNode?.onclick) { - e.stopPropagation(); - setTimeout( - action(() => (this._marqueeing = undefined)), - 100 - ); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it. - } else { - this._isAnnotating = true; - this.props.select(false); - e.stopPropagation(); + + if (!word && !(e.target as any)?.className?.includes('rangeslider') && !(e.target as any)?.onclick && !(e.target as any)?.parentNode?.onclick) { + if (e.button !== 2) this.marqueeing = [e.clientX, e.clientY]; e.preventDefault(); } document.addEventListener('pointerup', this.webClipUp); }; + @action webClipUp = (e: PointerEvent) => { + if (window.getSelection()?.isCollapsed && this._marqueeref.current?.isEmpty) { + this.marqueeing = undefined; + } document.removeEventListener('pointerup', this.webClipUp); this._getAnchor = AnchorMenu.Instance?.GetAnchor; // need to save AnchorMenu's getAnchor since a subsequent selection on another doc will overwrite this value const sel = window.getSelection(); @@ -382,7 +391,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.createTextAnnotation(sel, selRange); - AnchorMenu.Instance.jumpTo(e.clientX, e.clientY); + (!sel.isCollapsed || this.marqueeing) && AnchorMenu.Instance.jumpTo(e.clientX, e.clientY); // Changing which document to add the annotation to (the currently selected WebBox) GPTPopup.Instance.setSidebarId(`${this.props.fieldKey}_${this._urlHash ? this._urlHash + '_' : ''}sidebar`); GPTPopup.Instance.addDoc = this.sidebarAddDocument; @@ -390,36 +399,26 @@ export class WebBox extends ViewBoxAnnotatableComponent { - const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); - const scale = (this.props.NativeDimScaling?.() || 1) * mainContBounds.scale; - const word = getWordAtPoint(e.target, e.clientX, e.clientY); - this._setPreviewCursor?.(e.clientX, e.clientY, false, true, this.rootDoc); + this.props.select(false); + const locpt = { + x: (e.clientX / NumCast(this.rootDoc.nativeWidth)) * this.props.PanelWidth(), + y: ((e.clientY - NumCast(this.rootDoc.layout_scrollTop))/ NumCast(this.rootDoc.nativeHeight)) * this.props.PanelHeight() }; // prettier-ignore + const scrclick = this.props.DocumentView?.().props.ScreenToLocalTransform().inverse().transformPoint(locpt.x, locpt.y)!; + const scrcent = this.props + .DocumentView?.() + .props.ScreenToLocalTransform() + .inverse() + .transformPoint(NumCast(this.rootDoc.width) / 2, NumCast(this.rootDoc.height) / 2)!; + const theclickoff = Utils.rotPt(scrclick[0] - scrcent[0], scrclick[1] - scrcent[1], -this.props.ScreenToLocalTransform().Rotate); + const theclick = [theclickoff.x + scrcent[0], theclickoff.y + scrcent[1]]; MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - e.button !== 2 && (this._marqueeing = [e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._layout_scrollTop) * scale]); - if (word || (e.target as any)?.className?.includes('rangeslider') || (e.target as any)?.onclick || (e.target as any)?.parentNode?.onclick) { - setTimeout( - action(() => (this._marqueeing = undefined)), - 100 - ); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it. - } else { - this._iframeClick = this._iframe ?? undefined; - this._isAnnotating = true; - this.props.select(false); - e.stopPropagation(); - e.preventDefault(); - } - - // bcz: hack - iframe grabs all events which messes up how we handle contextMenus. So this super naively simulates the event stack to get the specific menu items and the doc view menu items. - if (e.button === 2 || (e.button === 0 && e.altKey)) { + const word = getWordAtPoint(e.target, e.clientX, e.clientY); + if (!word && !(e.target as any)?.className?.includes('rangeslider') && !(e.target as any)?.onclick && !(e.target as any)?.parentNode?.onclick) { + this.marqueeing = theclick; e.preventDefault(); - //e.stopPropagation(); - ContextMenu.Instance.closeMenu(); - ContextMenu.Instance.setIgnoreEvents(true); } }; isFirefox = () => 'InstallTrigger' in window; // navigator.userAgent.indexOf("Chrome") !== -1; - iframeClick = () => this._iframeClick; - iframeScaling = () => 1 / this.props.ScreenToLocalTransform().Scale; addWebStyleSheet(document: any, styleType: string = 'text/css') { if (document) { @@ -723,38 +722,56 @@ export class WebBox extends ViewBoxAnnotatableComponent { + const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection(); + this._textAnnotationCreator = undefined; + if (sel?.empty) 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(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - this._marqueeing = [e.clientX, e.clientY]; return true; }), returnFalse, - () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), + action(() => { + this.marqueeing = undefined; + MarqueeAnnotator.clearAnnotations(this._savedAnnotations); + }), false ); + } else { + this.marqueeing = undefined; } }; @action finishMarquee = (x?: number, y?: number, e?: PointerEvent) => { this._getAnchor = AnchorMenu.Instance?.GetAnchor; - this._marqueeing = undefined; - this._isAnnotating = false; - this._iframeClick = undefined; + this.marqueeing = undefined; + this._textAnnotationCreator = undefined; const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection(); if (sel?.empty) sel.empty(); // Chrome else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox + this._setPreviewCursor?.(x ?? 0, y ?? 0, false, !this._marqueeref.current?.isEmpty, this.rootDoc); if (x !== undefined && y !== undefined) { - this._setPreviewCursor?.(x, y, false, false, this.rootDoc); ContextMenu.Instance.closeMenu(); ContextMenu.Instance.setIgnoreEvents(false); if (e?.button === 2 || e?.altKey) { - this.specificContextMenu(undefined as any); - this.props.docViewPath().lastElement().docView?.onContextMenu(undefined, x, y); + e?.preventDefault(); + e?.stopPropagation(); + setTimeout(() => { + // if menu comes up right away, the down event can still be active causing a menu item to be selected + this.specificContextMenu(undefined as any); + this.props.docViewPath().lastElement().docView?.onContextMenu(undefined, x, y); + }); } } }; @@ -797,7 +814,7 @@ export class WebBox extends ViewBoxAnnotatableComponent (this._iframe = r))} - style={{ pointerEvents: this._isAnyChildContentActive || DocumentView.Interacting ? 'none' : undefined }} + style={{ pointerEvents: DocumentView.Interacting ? 'none' : undefined }} src={url} onLoad={this.iframeLoaded} scrolling="no" // ugh.. on windows, I get an inner scroll bar for the iframe's body even though the scrollHeight should be set to the full height of the document. @@ -942,7 +959,7 @@ export class WebBox extends ViewBoxAnnotatableComponent NumCast(a.y) - NumCast(b.y)) .map(anno => ( - + ))}
); @@ -1004,7 +1021,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.setDashScrollTop(this._outerRef.current?.scrollTop || 0)} onPointerDown={this.onMarqueeDown}> -
+
this.props.PanelHeight() && this._scrollHeight) || '100%', pointerEvents }}> {this.content}
{this.renderTransparentAnnotations}
{this.renderOpaqueAnnotations} @@ -1049,7 +1066,6 @@ export class WebBox extends ViewBoxAnnotatableComponent) => (this._searchString = e.currentTarget.value); - showInfo = action((anno: Opt) => (this._overlayAnnoInfo = anno)); setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void) => (this._setPreviewCursor = func); panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth; panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); @@ -1067,7 +1083,7 @@ export class WebBox extends ViewBoxAnnotatableComponent (this.props.isContentActive() && (this._isAnnotating || SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None) ? 'all' : 'none'); + annotationPointerEvents = () => (this.props.isContentActive() && (SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None) ? 'all' : 'none'); render() { const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any); @@ -1090,27 +1106,26 @@ export class WebBox extends ViewBoxAnnotatableComponent {this.webpage} - {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( -
- -
- )}
+ {!this._mainCont.current || !this._annotationLayer.current ? null : ( +
+ +
+ )}
() { let dataField = Doc.LayoutFieldKey(tagDoc); if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '_annotations'; - if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc.annotationOn["${dataField}"]`); - else activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc["${dataField}"]`); + if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc.annotationOn?.["${dataField}"]`); + else activeItem.data = ComputedField.MakeFunction(`self.presentation_targetDoc?.["${dataField}"]`); }} checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined ? true : false} /> diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 38e4f65b6..e1e87763c 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -12,12 +12,13 @@ import { FieldViewProps } from '../nodes/FieldView'; import { AnchorMenu } from './AnchorMenu'; import './Annotation.scss'; import { LinkManager } from '../../util/LinkManager'; +import { Rect } from 'react-measure'; interface IAnnotationProps extends FieldViewProps { anno: Doc; dataDoc: Doc; fieldKey: string; - showInfo: (anno: Opt) => void; + showInfo?: (anno: Opt) => void; pointerEvents?: () => Opt; } @observer @@ -69,18 +70,24 @@ class RegionAnnotation extends React.Component { } }; + @action + onContextMenu = (e: React.MouseEvent) => { + AnchorMenu.Instance.Status = 'annotation'; + AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this); + AnchorMenu.Instance.Pinned = false; + AnchorMenu.Instance.PinToPres = this.pinToPres; + AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle; + AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler; + AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.annoTextRegion); + AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true); + e.stopPropagation(); + e.preventDefault(); + }; @action onPointerDown = (e: React.PointerEvent) => { if (e.button === 2 || e.ctrlKey) { - AnchorMenu.Instance.Status = 'annotation'; - AnchorMenu.Instance.Delete = this.deleteAnnotation.bind(this); - AnchorMenu.Instance.Pinned = false; - AnchorMenu.Instance.PinToPres = this.pinToPres; - AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle; - AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler; - AnchorMenu.Instance.ShowTargetTrail = () => this.showTargetTrail(this.annoTextRegion); - AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true); e.stopPropagation(); + e.preventDefault(); } else if (e.button === 0) { e.stopPropagation(); LinkFollower.FollowLink(undefined, this.annoTextRegion, false); @@ -102,13 +109,14 @@ class RegionAnnotation extends React.Component { ref={this._mainCont} onPointerEnter={action(() => { Doc.BrushDoc(this.props.anno); - this.props.showInfo(this.props.anno); + this.props.showInfo?.(this.props.anno); })} onPointerLeave={action(() => { Doc.UnBrushDoc(this.props.anno); - this.props.showInfo(undefined); + this.props.showInfo?.(undefined); })} onPointerDown={this.onPointerDown} + onContextMenu={this.onContextMenu} style={{ left: NumCast(this.props.document.x), top: NumCast(this.props.document.y), diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index a66e519c9..ca9bf7bd2 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -2,7 +2,7 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reactio import { observer } from 'mobx-react'; import * as Pdfjs from 'pdfjs-dist'; import 'pdfjs-dist/web/pdf_viewer.css'; -import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc'; +import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { Height } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; @@ -11,7 +11,6 @@ import { TraceMobx } from '../../../fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, returnAll, returnFalse, returnNone, returnZero, smoothScroll, Utils } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { SelectionManager } from '../../util/SelectionManager'; -import { SharingManager } from '../../util/SharingManager'; import { SnappingManager } from '../../util/SnappingManager'; import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; @@ -56,16 +55,15 @@ export class PDFViewer extends React.Component { static _annotationStyle: any = addStyleSheet(); @observable private _pageSizes: { width: number; height: number }[] = []; @observable private _savedAnnotations = new ObservableMap(); - @observable private _marqueeing: number[] | undefined; @observable private _textSelecting = true; @observable private _showWaiting = true; - @observable private _overlayAnnoInfo: Opt; @observable private Index: number = -1; private _pdfViewer: any; private _styleRule: any; // stylesheet rule for making hyperlinks clickable private _retries = 0; // number of times tried to create the PDF viewer private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void); + private _marqueeref = React.createRef(); private _annotationLayer: React.RefObject = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; private _viewer: React.RefObject = React.createRef(); @@ -368,17 +366,14 @@ export class PDFViewer extends React.Component { if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { this.props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - this._marqueeing = [e.clientX, e.clientY]; + this._marqueeref.current?.onInitiateSelection([e.clientX, e.clientY]); this.isAnnotating = true; const target = e.target as any; if (e.target && (target.className.includes('endOfContent') || (target.parentElement.className !== 'textLayer' && target.parentElement.parentElement?.className !== 'textLayer'))) { this._textSelecting = false; } else { // if textLayer is hit, then we select text instead of using a marquee so clear out the marquee. - setTimeout( - action(() => (this._marqueeing = undefined)), - 100 - ); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it. + setTimeout(() => this._marqueeref.current?.onTerminateSelection(), 100); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it. this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, 'htmlAnnotation', { 'pointer-events': 'none' }); document.addEventListener('pointerup', this.onSelectEnd); @@ -390,7 +385,7 @@ export class PDFViewer extends React.Component { finishMarquee = (x?: number, y?: number) => { this._getAnchor = AnchorMenu.Instance?.GetAnchor; this.isAnnotating = false; - this._marqueeing = undefined; + this._marqueeref.current?.onTerminateSelection(); this._textSelecting = true; }; @@ -420,23 +415,26 @@ export class PDFViewer extends React.Component { @action createTextAnnotation = (sel: Selection, selRange: Range) => { if (this._mainCont.current) { + this._mainCont.current.style.transform = `rotate(${NumCast(this.props.DocumentView!().screenToLocalTransform().RotateDeg)}deg)`; const boundingRect = this._mainCont.current.getBoundingClientRect(); const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { const rect = clientRects.item(i); - if (rect?.width && rect.width < this._mainCont.current.clientWidth / this.props.ScreenToLocalTransform().Scale) { + if (rect && rect?.width && rect.width < this._mainCont.current.clientWidth / this.props.ScreenToLocalTransform().Scale) { const scaleX = this._mainCont.current.offsetWidth / boundingRect.width; + const scaleY = this._mainCont.current.offsetHeight / boundingRect.height; const pdfScale = NumCast(this.props.layoutDoc._freeform_scale, 1); const annoBox = document.createElement('div'); annoBox.className = 'marqueeAnnotator-annotationBox'; // transforms the positions from screen onto the pdf div - annoBox.style.top = (((rect.top - boundingRect.top) * scaleX) / pdfScale + this._mainCont.current.scrollTop).toString(); annoBox.style.left = (((rect.left - boundingRect.left) * scaleX) / pdfScale).toString(); - annoBox.style.width = ((rect.width * this._mainCont.current.offsetWidth) / boundingRect.width / pdfScale).toString(); - annoBox.style.height = ((rect.height * this._mainCont.current.offsetHeight) / boundingRect.height / pdfScale).toString(); + annoBox.style.top = (((rect.top - boundingRect.top) * scaleY) / pdfScale + this._mainCont.current.scrollTop).toString(); + annoBox.style.width = ((rect.width * scaleX) / pdfScale).toString(); + annoBox.style.height = ((rect.height * scaleY) / pdfScale).toString(); this._annotationLayer.current && MarqueeAnnotator.previewNewAnnotation(this._savedAnnotations, this._annotationLayer.current, annoBox, this.getPageFromScroll(rect.top)); } } + this._mainCont.current!.style.transform = ''; } this._selectionContent = selRange.cloneContents(); this._selectionText = this._selectionContent?.textContent || ''; @@ -482,24 +480,13 @@ export class PDFViewer extends React.Component { return (
{inlineAnnos.map(anno => ( - + ))}
); } - @computed get overlayInfo() { - return !this._overlayAnnoInfo ? null : ( -
-
users.user.email === this._overlayAnnoInfo!.author)?.userColor }}> - {this._overlayAnnoInfo.author + ' ' + Field.toString(this._overlayAnnoInfo.author_date as Field)} -
-
- ); - } - getScrollHeight = () => this._scrollHeight; - showInfo = action((anno: Opt) => (this._overlayAnnoInfo = anno)); scrollXf = () => (this._mainCont.current ? this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.layoutDoc._layout_scrollTop)) : this.props.ScreenToLocalTransform()); overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._freeform_scale, 1)); panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1); @@ -567,6 +554,7 @@ export class PDFViewer extends React.Component { return
; } savedAnnotations = () => this._savedAnnotations; + addDocumentWrapper = (doc: Doc | Doc[]) => this.props.addDocument!(doc); render() { TraceMobx(); return ( @@ -585,17 +573,17 @@ export class PDFViewer extends React.Component { {this.pdfViewerDiv} {this.annotationLayer} {this.overlayLayer} - {this.overlayInfo} {this._showWaiting ? : null} - {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this._annotationLayer.current ? null : ( this.props.addDocument!(doc)} - docView={this.props.docViewPath().lastElement()} + annotationLayerScrollTop={NumCast(this.props.Document._layout_scrollTop)} + addDocument={this.addDocumentWrapper} + docView={this.props.DocumentView!} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} selectionText={this.selectionText} -- cgit v1.2.3-70-g09d2 From ac360607bee82f0fef769eada99dc0b3f85ae70a Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 27 Nov 2023 13:46:27 -0500 Subject: fixed dataView to not lose focus when typing 'enter' by fixing freeformdocumentview panelwidth() to --- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 4 ++-- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 10 +++++----- src/fields/Doc.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 2e66c9012..7f8bde9b4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1289,8 +1289,8 @@ export class CollectionFreeFormView extends CollectionSubView this.Transition; // prettier-ignore w_DataTransition = () => this.DataTransition; // prettier-ignore - PanelWidth = () => this.Width || this.props.PanelWidth?.(); // prettier-ignore - PanelHeight = () => this.Height || this.props.PanelHeight?.(); // prettier-ignore + PanelWidth = () => this.Width > 0 ? this.Width : this.props.PanelWidth?.(); // prettier-ignore + PanelHeight = () => this.Height > 0 ? this.Height : this.props.PanelHeight?.(); // prettier-ignore @action componentDidUpdate() { this.WrapperKeys.forEach(keys => ((this as any)[keys.upper] = (this.props as any)[keys.lower])); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 368aaa5db..e2746091e 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1059,7 +1059,7 @@ export namespace Doc { } export function NativeHeight(doc?: Doc, dataDoc?: Doc, useHeight?: boolean) { if (!doc) return 0; - const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * NumCast(doc._height)) / NumCast(doc._width); + const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) / NumCast(doc._width)) * NumCast(doc._height); // divide before multiply to avoid floating point errrorin case nativewidth = width const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '_nativeHeight'], useHeight ? NumCast(doc._height) : 0); return NumCast(doc._nativeHeight, nheight || dheight); } -- cgit v1.2.3-70-g09d2 From ba3b3f6f261074bd3f35012bde8730f5d4a36905 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 29 Nov 2023 10:02:34 -0500 Subject: numerous changes to fix bugs and to fix/remove old or hacky code. fixed doc dec resizing. moving this.rootDoc => this.Document . fixing template artifacts. --- src/client/documents/Documents.ts | 19 +- src/client/util/CurrentUserUtils.ts | 96 +-- src/client/util/Scripting.ts | 4 +- src/client/views/DashboardView.tsx | 2 +- src/client/views/DocComponent.tsx | 16 +- src/client/views/DocumentButtonBar.tsx | 14 +- src/client/views/DocumentDecorations.tsx | 18 +- src/client/views/GlobalKeyHandler.ts | 4 +- src/client/views/MainView.tsx | 6 +- src/client/views/MarqueeAnnotator.tsx | 26 +- src/client/views/PropertiesButtons.tsx | 5 +- src/client/views/PropertiesView.tsx | 47 +- src/client/views/StyleProvider.tsx | 9 +- .../views/collections/CollectionDockingView.tsx | 53 +- src/client/views/collections/CollectionMenu.tsx | 824 +-------------------- .../views/collections/CollectionNoteTakingView.tsx | 4 +- .../views/collections/CollectionPileView.tsx | 16 +- .../collections/CollectionStackedTimeline.tsx | 16 +- .../views/collections/CollectionStackingView.scss | 2 +- .../views/collections/CollectionStackingView.tsx | 96 ++- src/client/views/collections/CollectionSubView.tsx | 20 +- .../views/collections/CollectionTimeView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 16 +- src/client/views/collections/TabDocView.tsx | 4 +- src/client/views/collections/TreeView.tsx | 13 +- .../CollectionFreeFormLayoutEngines.tsx | 1 + .../CollectionFreeFormPannableContents.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 199 ++--- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../collectionGrid/CollectionGridView.tsx | 5 +- .../collectionLinear/CollectionLinearView.tsx | 8 +- .../CollectionMulticolumnView.scss | 2 +- .../CollectionMulticolumnView.tsx | 39 +- .../CollectionMultirowView.scss | 5 - .../CollectionMultirowView.tsx | 37 +- .../collectionSchema/CollectionSchemaView.tsx | 10 +- .../collectionSchema/SchemaTableCell.tsx | 3 +- src/client/views/global/globalScripts.ts | 8 +- src/client/views/nodes/AudioBox.tsx | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 51 +- src/client/views/nodes/DocumentContentsView.tsx | 23 +- src/client/views/nodes/DocumentView.tsx | 171 +++-- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 121 ++- src/client/views/nodes/FunctionPlotBox.tsx | 6 +- src/client/views/nodes/ImageBox.tsx | 3 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/LinkBox.tsx | 18 +- src/client/views/nodes/MapBox/MapPushpinBox.tsx | 6 +- src/client/views/nodes/PDFBox.tsx | 1 - .../views/nodes/RecordingBox/RecordingBox.tsx | 12 +- src/client/views/nodes/ScreenshotBox.tsx | 4 +- src/client/views/nodes/ScriptingBox.tsx | 6 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 53 +- .../views/nodes/formattedText/RichTextMenu.tsx | 46 +- .../views/nodes/formattedText/RichTextRules.ts | 2 +- src/client/views/nodes/trails/PresBox.tsx | 97 ++- src/client/views/nodes/trails/PresElementBox.tsx | 64 +- src/client/views/pdf/PDFViewer.tsx | 5 +- src/client/views/search/SearchBox.tsx | 2 +- src/fields/Doc.ts | 15 +- src/fields/ScriptField.ts | 26 +- 63 files changed, 798 insertions(+), 1605 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 029653204..4def19384 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -292,6 +292,7 @@ export class DocumentOptions { childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox layout in tree view) childLayoutString?: string; // template string for collection to use to render its children childDocumentsActive?: BOOLt = new BoolInfo('whether child documents are active when parent is document active'); + childLayoutFitWidth?: BOOLt = new BoolInfo("whether a child doc's fitWith should be overriden by collection"); childDontRegisterViews?: BOOLt = new BoolInfo('whether child document views should be registered so that they can be found when following links, etc'); childHideLinkButton?: BOOLt = new BoolInfo('hide link buttons on all children'); childContextMenuFilters?: List; @@ -1134,7 +1135,7 @@ export namespace Docs { // } export function FreeformDocument(documents: Array, options: DocumentOptions, id?: string) { - const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _type_collection: CollectionViewType.Freeform }, id); + const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _type_collection: CollectionViewType.Freeform }, id); documents.forEach(d => Doc.SetContainer(d, inst)); return inst; } @@ -1217,7 +1218,7 @@ export namespace Docs { } export function FunctionPlotDocument(documents: Array, options?: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.FUNCPLOT), new List(documents), { ...(options || {}) }); + return InstanceFromProto(Prototypes.get(DocumentType.FUNCPLOT), new List(documents), { title: 'func plot', ...(options || {}) }); } export function ButtonDocument(options?: DocumentOptions) { @@ -1487,7 +1488,7 @@ export namespace DocUtils { Object.keys(scripts).map(key => { const script = scripts[key]; if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && script) { - doc[key] = ScriptField.MakeScript(script, { + (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = ScriptField.MakeScript(script, { self: Doc.name, this: Doc.name, dragData: DragManager.DocumentDragData.name, @@ -1511,7 +1512,7 @@ export namespace DocUtils { const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); if (ScriptCast(cfield)?.script.originalScript !== funcs[key]) { const setFunc = Cast(funcs[key + '-setter'], 'string', null); - doc[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }, setFunc) : undefined; + (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: DragManager.DocumentDragData.name }, { _readOnly_: true }, setFunc) : undefined; } }); return doc; @@ -1717,7 +1718,7 @@ export namespace DocUtils { } export function createCustomView(doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = 'custom', docLayoutTemplate?: Doc) { const templateName = templateSignature.replace(/\(.*\)/, ''); - docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc._isGroup && doc.transcription ? 'transcription' : doc.type), templateSignature); + docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc.isGroup && doc.transcription ? 'transcription' : doc.type), templateSignature); const customName = 'layout_' + templateSignature; const _width = NumCast(doc._width); @@ -1987,9 +1988,9 @@ ScriptingGlobals.add(function makeDelegate(proto: any) { const d = Docs.Create.DelegateDocument(proto, { title: 'child of ' + proto.title }); return d; }); -ScriptingGlobals.add(function generateLinkTitle(self: Doc) { - const link_anchor_1title = self.link_anchor_1 && self.link_anchor_1 !== self ? Cast(self.link_anchor_1, Doc, null)?.title : ''; - const link_anchor_2title = self.link_anchor_2 && self.link_anchor_2 !== self ? Cast(self.link_anchor_2, Doc, null)?.title : ''; - const relation = self.link_relationship || 'to'; +ScriptingGlobals.add(function generateLinkTitle(link: Doc) { + const link_anchor_1title = link.link_anchor_1 && link.link_anchor_1 !== link ? Cast(link.link_anchor_1, Doc, null)?.title : ''; + const link_anchor_2title = link.link_anchor_2 && link.link_anchor_2 !== link ? Cast(link.link_anchor_2, Doc, null)?.title : ''; + const relation = link.link_relationship || 'to'; return `${link_anchor_1title} (${relation}) ${link_anchor_2title}`; }); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 18c7a1fb6..2f2ac2a71 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -284,7 +284,7 @@ export class CurrentUserUtils { treeView_HasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, dropAction:'move', treeView_Type: TreeViewType.outline, backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true - }, funcs: {title: 'self.text?.Text'}}, + }, funcs: {title: 'this.text?.Text'}}, ]; emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs)); @@ -339,7 +339,7 @@ export class CurrentUserUtils { /// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] { - const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target?.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())"; + const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(this.target?.data).filter(doc => !docList(this.target.viewed).includes(doc)).length.toString())"; const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails"; return [ { title: "Dashboards", toolTip: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), ignoreClick: true, icon: "desktop", funcs: {hidden: "IsNoviceMode()"} }, @@ -467,6 +467,7 @@ export class CurrentUserUtils { const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined); const reqdToolOps:DocumentOptions = { title: "My Tools", isSystem: true, ignoreClick: true, layout_boxShadow: "0 0", + layout_explainer: "This is a palette of documents that can be created.", _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, _chromeHidden: true, }; return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdToolOps, [creatorBtns, templateBtns]); @@ -558,7 +559,7 @@ export class CurrentUserUtils { const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _dragOnlyWithinContainer: true, _layout_hideContextMenu: true, title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton, color: Colors.BLACK, buttonText: "Empty", icon: "trash", isSystem: true, toolTip: "Empty recently closed",}; - DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")}); + DocUtils.AssignDocField(recentlyClosed, "layout_headerButton", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("this.target")}); if (!Cast(recentlyClosed.contextMenuScripts, listSpec(ScriptField),null)?.find((script) => script.script.originalScript === clearAll("self"))) { recentlyClosed.contextMenuScripts = new List([ScriptField.MakeScript(clearAll("self"))!]) @@ -628,42 +629,42 @@ export class CurrentUserUtils { } static stackTools(): Button[] { return [ - { title: "Center", icon: "align-center", toolTip: "Center Align Stack", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"center", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Center", icon: "align-center", toolTip: "Center Align Stack", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"center", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform ] } static viewTools(): Button[] { return [ - { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "View All", icon: "object-group", toolTip: "Keep all Docs in View",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "View All", icon: "object-group", toolTip: "Keep all Docs in View",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform // want the same style as toggle button, but don't want it to act as an actual toggle, so set disableToggle to true, - { title: "Fit All", icon: "arrows-left-right", toolTip: "Fit Docs to View (once)",btnType: ButtonType.ClickButton,ignoreClick:false,expertMode: false, toolType:"fitOnce", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(self.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Fit All", icon: "arrows-left-right", toolTip: "Fit Docs to View (once)",btnType: ButtonType.ClickButton,ignoreClick:false,expertMode: false, toolType:"fitOnce", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform ] } static textTools():Button[] { return [ - { title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, toolType:"font", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, + { title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, toolType:"font", ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}, btnList: new List(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) }, - { title: "Font Size",toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 6 }, - { title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}}, - { title: "Highlight",toolTip: "Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} }, - { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", toolType:"bold", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", toolType:"italics", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, + { title: "Font Size",toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 6 }, + { title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}}, + { title: "Highlight",toolTip: "Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} }, + { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", toolType:"bold", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", toolType:"italics", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, { title: "Align", toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true, subMenu: [ - { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }}, - { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, - { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, + { title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}' }}, + { title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, + { title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'} }, ]}, - { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}}, - { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}}, + { title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}}, + { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(this.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}}, // { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}}, // { title: "Superscript", tooltip: "Superscript", btnType: ButtonType.ToggleButton, icon: "superscript", scripts: {onClick:: 'toggleSuperscript()'}}, // { title: "Subscript", tooltip: "Subscript", btnType: ButtonType.ToggleButton, icon: "subscript", scripts: {onClick:: 'toggleSubscript()'}}, @@ -672,15 +673,15 @@ export class CurrentUserUtils { static inkTools():Button[] { return [ - { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", toolType: "pen", scripts: {onClick:'{ return setActiveTool(self.toolType, false, _readOnly_);}' }}, - { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", toolType: "write", scripts: {onClick:'{ return setActiveTool(self.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, - { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", toolType: "eraser", scripts: {onClick:'{ return setActiveTool(self.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, - { title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", toolType:GestureUtils.Gestures.Circle, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, - { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", toolType:GestureUtils.Gestures.Rectangle, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, - { title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", toolType:GestureUtils.Gestures.Line, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, - { title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask", scripts: {onClick:'{ return setInkProperty(self.toolType, value, _readOnly_);}'}, funcs: {hidden:"IsNoviceMode()" } }, - { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'}, numBtnMin: 1}, - { title: "Ink", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'} }, + { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", toolType: "pen", scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' }}, + { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", toolType: "write", scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, + { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", toolType: "eraser", scripts: {onClick:'{ return setActiveTool(this.toolType, false, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }}, + { title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", toolType:GestureUtils.Gestures.Circle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, + { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", toolType:GestureUtils.Gestures.Rectangle, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, + { title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", toolType:GestureUtils.Gestures.Line, scripts: {onClick:`{ return setActiveTool(this.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(this.toolType, true, _readOnly_);}`} }, + { title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask", scripts: {onClick:'{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"IsNoviceMode()" } }, + { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, numBtnMin: 1}, + { title: "Ink", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'} }, ]; } @@ -709,17 +710,17 @@ export class CurrentUserUtils { { title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 30, scripts: { onClick: 'pinWithView(altKey)'}, funcs: {hidden: "IsNoneSelected()"}}, { title: "Header", icon: "heading", toolTip: "Doc Titlebar Color", btnType: ButtonType.ColorButton, expertMode: true, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'} }, { title: "Fill", icon: "fill-drip", toolTip: "Fill/Background Color",btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}, funcs: {hidden: "IsNoneSelected()"}}, // Only when a document is selected - { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform - { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}}, - { title: "Num", icon:"", toolTip: "Frame Number (click to toggle edit mode)", btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}}, - { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}}, - { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available - { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available - { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected - { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Schema is selected + { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform + { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}}, + { title: "Num", icon:"", toolTip: "Frame # (click to toggle edit mode)",btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}}, + { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}}, + { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available + { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected + { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected ]; } @@ -904,7 +905,7 @@ export class CurrentUserUtils { this.setupDocTemplates(doc); // sets up the template menu of templates //this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) => Docs.Prototypes.MainScriptDocument(), {}); - DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents + DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "My Header Bar", isSystem: true, _chromeHidden:true, childLayoutFitWidth:false, childDocumentsActive:false, dropAction: 'move'}); // drop down panel at top of dashboard for stashing documents Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MyDashboards) Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs) @@ -976,6 +977,7 @@ export class CurrentUserUtils { DashboardView.createNewDashboard(undefined, "guest dashboard"); } else { userDoc.activePage = "home"; + userDoc.noviceMode = true; } } return userDoc; diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 70c2e3842..400b63a1c 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -264,6 +264,6 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp } ScriptingGlobals.add(CompileScript); -ScriptingGlobals.add(function runScript(self: Doc, script: ScriptField) { - return script?.script.run({ this: self, self: self }).result; +ScriptingGlobals.add(function runScript(doc: Doc, script: ScriptField) { + return script?.script.run({ this: doc }).result; }); diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 9e2ed7822..2765e95e6 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -370,7 +370,7 @@ export class DashboardView extends React.Component { const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row'); - Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc, undefined, undefined, true); dashboardDoc['pane-count'] = 1; freeformDoc.embedContainer = dashboardDoc; dashboardDoc.myOverlayDocs = new List(); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index fdaca8056..61b7a3bff 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -10,6 +10,8 @@ import { DocUtils } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentView } from './nodes/DocumentView'; import * as React from 'react'; +import { DocumentManager } from '../util/DocumentManager'; +import { CollectionFreeFormView } from './collections/collectionFreeForm'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) export interface DocComponentProps { @@ -26,7 +28,7 @@ export function DocComponent

() { } // This is the "The Document" -- it encapsulates, data, layout, and any templates @computed get rootDoc() { - return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; + return this.props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info @computed get layoutDoc() { @@ -58,7 +60,9 @@ export function ViewBoxBaseComponent

() { class Component extends React.Component> { //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then //@computed get Document(): T { return schemaCtor(this.props.Document); } - + @computed get Document() { + return this.props.Document; + } // This is the "The Document" -- it encapsulates, data, layout, and any templates @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; @@ -146,7 +150,11 @@ export function ViewBoxAnnotatableComponent

() doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true); } }); - this.isAnyChildContentActive() && this.props.select(false); + if (targetDataDoc.isGroup && DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]).length < 2) { + (DocumentManager.Instance.getFirstDocumentView(targetDataDoc)?.ComponentView as CollectionFreeFormView)?.promoteCollection(); + } else { + this.isAnyChildContentActive() && this.props.select(false); + } return true; } @@ -173,7 +181,7 @@ export function ViewBoxAnnotatableComponent

() if (this.props.filterAddDocument?.(docs) === false || docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document) && Doc.LayoutField(doc) === Doc.LayoutField(this.props.Document))) { return false; } - const targetDataDoc = this.rootDoc[DocData]; + const targetDataDoc = this.dataDoc; const effectiveAcl = GetEffectiveAcl(targetDataDoc); if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index c1ec5b4a4..bd82f7782 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -574,12 +574,12 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV e.stopPropagation(); }; render() { - if (!this.view0) return null; - - const isText = this.view0.props.Document[this.view0.LayoutFieldKey] instanceof RichTextField; const doc = this.view0?.props.Document; - const considerPull = isText && this.considerGoogleDocsPull; - const considerPush = isText && this.considerGoogleDocsPush; + if (!doc || !this.view0) return null; + + const isText = () => doc[this.view0!.LayoutFieldKey] instanceof RichTextField; + const considerPull = () => isText() && this.considerGoogleDocsPull; + const considerPush = () => isText() && this.considerGoogleDocsPush; return (

@@ -608,11 +608,11 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
{this.recordButton}
{!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null :
{this.shareButton}
} {!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null : ( -
+
{this.considerGoogleDocsPush}
)} -
+
{this.considerGoogleDocsPull}
{this.menuButton}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d4b474de9..4ede2e2bb 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -6,7 +6,7 @@ import { observer } from 'mobx-react'; import { FaUndo } from 'react-icons/fa'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; -import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols'; +import { AclAdmin, AclAugment, AclEdit } from '../../fields/DocSymbols'; import { InkField } from '../../fields/InkField'; import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; @@ -71,10 +71,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P e.clientY - center.y, NumCast(SelectionManager.Views().lastElement()?.screenToLocalTransform().Rotate)); (this._showNothing = !(this.Bounds.x !== Number.MAX_VALUE && // - (this.Bounds.x > center.x+x + this._resizeBorderWidth / 2 || - this.Bounds.r < center.x+x - this._resizeBorderWidth / 2 || - this.Bounds.y > center.y+y + this._resizeBorderWidth / 2 || - this.Bounds.b < center.y+y - this._resizeBorderWidth / 2))); + (this.Bounds.x > center.x+x || this.Bounds.r < center.x+x || + this.Bounds.y > center.y+y || this.Bounds.b < center.y+y ))); })); // prettier-ignore } @@ -551,8 +549,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (setData) Doc.SetNativeHeight(Doc.GetProto(doc), NumCast(doc._nativeHeight)); } - doc._width = NumCast(doc._width) * scale.x; - doc._height = NumCast(doc._height) * scale.y; + doc._width = Math.max(1, NumCast(doc._width) * scale.x); + doc._height = Math.max(1, NumCast(doc._height) * scale.y); const { deltaX, deltaY } = this.realignRefPt(doc, refCent, initWidth, initHeight); doc.x = NumCast(doc.x) + deltaX; doc.y = NumCast(doc.y) + deltaY; @@ -675,7 +673,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P seldocview.props.hideDeleteButton || seldocview.rootDoc.hideDeleteButton || SelectionManager.Views().some(docView => { - const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DocData]) : AclEdit; + const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().dataDoc) : AclEdit; return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin; }); const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => ( @@ -801,11 +799,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
- {seldocview.props.renderDepth <= 1 || !seldocview.props.docViewPath().lastElement() - ? null - : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')} )} + {seldocview.props.renderDepth <= 1 || !seldocview.props.docViewPath().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')} {useRounding && (
{SnappingManager.horizSnapLines().map((l, i) => ( - + ))} {SnappingManager.vertSnapLines().map((l, i) => ( - + ))}
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 20c7a08fa..8b8838464 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable, ObservableMap, runInAction, trace } from 'mobx'; +import { action, computed, observable, ObservableMap } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocData } from '../../fields/DocSymbols'; @@ -19,7 +19,7 @@ import React = require('react'); const _global = (window /* browser */ || global) /* node */ as any; export interface MarqueeAnnotatorProps { - rootDoc: Doc; + Document: Doc; down?: number[]; scrollTop: number; scaling?: () => number; @@ -69,8 +69,8 @@ export class MarqueeAnnotator extends React.Component { const marqueeAnno = Docs.Create.FreeformDocument([], { onClick: isLinkButton ? FollowLinkScript() : undefined, backgroundColor: color, - annotationOn: this.props.rootDoc, - title: 'Annotation on ' + this.props.rootDoc.title, + annotationOn: this.props.Document, + title: 'Annotation on ' + this.props.Document.title, }); marqueeAnno.x = NumCast(doc.freeform_panX_min) + (parseInt(anno.style.left || '0') - containerOffset[0]) / scale; marqueeAnno.y = NumCast(doc.freeform_panY_min) + (parseInt(anno.style.top || '0') - containerOffset[1]) / scale; @@ -82,13 +82,13 @@ export class MarqueeAnnotator extends React.Component { } const textRegionAnno = Docs.Create.HTMLMarkerDocument([], { - annotationOn: this.props.rootDoc, + annotationOn: this.props.Document, text: this.props.selectionText(), backgroundColor: 'transparent', presentation_duration: 2100, presentation_transition: 500, presentation_zoomText: true, - title: 'Selection on ' + this.props.rootDoc.title, + title: 'Selection on ' + this.props.Document.title, }); let minX = Number.MAX_VALUE; let maxX = -Number.MAX_VALUE; @@ -126,7 +126,7 @@ export class MarqueeAnnotator extends React.Component { @action highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap, addAsAnnotation?: boolean, summarize?: boolean) => { // creates annotation documents for current highlights - const effectiveAcl = GetEffectiveAcl(this.props.rootDoc[DocData]); + const effectiveAcl = GetEffectiveAcl(this.props.Document[DocData]); const annotationDoc = [AclAugment, AclSelfEdit, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color, isLinkButton, savedAnnotations); addAsAnnotation && annotationDoc && this.props.addDocument(annotationDoc); return annotationDoc as Doc; @@ -146,11 +146,11 @@ export class MarqueeAnnotator extends React.Component { const center = { x: boundingRect.x + boundingRect.width / 2, y: boundingRect.y + boundingRect.height / 2 }; const downPt = Utils.rotPt(down[0] - center.x, down[1] - center.y, NumCast(this.props.docView().screenToLocalTransform().Rotate)); const scale = this.props.docView().props.ScreenToLocalTransform().Scale; - const scalex = this.props.mainCont.offsetWidth / NumCast(this.props.rootDoc.width); - const scaley = this.props.mainCont.offsetHeight / NumCast(this.props.rootDoc.height); + const scalex = this.props.mainCont.offsetWidth / NumCast(this.props.Document.width); + const scaley = this.props.mainCont.offsetHeight / NumCast(this.props.Document.height); // set marquee x and y positions to the spatially transformed position - return { x: scalex * (downPt.x + NumCast(this.props.rootDoc.width) / scale / 2) * scale, - y: scaley * (downPt.y + NumCast(this.props.rootDoc.height) / scale / 2) * scale + this.props.annotationLayerScrollTop }; // prettier-ignore + return { x: scalex * (downPt.x + NumCast(this.props.Document.width) / scale / 2) * scale, + y: scaley * (downPt.y + NumCast(this.props.Document.height) / scale / 2) * scale + this.props.annotationLayerScrollTop }; // prettier-ignore }; @action @@ -184,14 +184,14 @@ export class MarqueeAnnotator extends React.Component { const sourceAnchorCreator = () => this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true, undefined, true); // hyperlink color const targetCreator = (annotationOn: Doc | undefined) => { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); FormattedTextBox.SelectOnLoad = target[Id]; return target; }; DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docView(), sourceAnchorCreator, targetCreator), e.pageX, e.pageY, { dragComplete: e => { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; + e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.Document; e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 18f53b8e7..84b1bf038 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -42,12 +42,15 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get selectedDoc() { return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.rootDoc; } + @computed get selectedLayoutDoc() { + return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.layoutDoc; + } @computed get selectedTabView() { return !SelectionManager.SelectedSchemaDoc() && SelectionManager.Views().lastElement()?.topMost; } propertyToggleBtn = (label: (on?: any) => string, property: string, tooltip: (on?: any) => string, icon: (on?: any) => any, onClick?: (dv: Opt, doc: Doc, property: string) => void, useUserDoc?: boolean) => { - const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedDoc; + const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedLayoutDoc; const onPropToggle = (dv: Opt, doc: Doc, prop: string) => ((dv?.layoutDoc || doc)[prop] = (dv?.layoutDoc || doc)[prop] ? false : true); return !targetDoc ? null : ( { } @computed get selectedDoc() { - return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc || Doc.ActiveDashboard; + return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.Document || Doc.ActiveDashboard; + } + + @computed get selectedLayoutDoc() { + return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.layoutDoc || Doc.ActiveDashboard; } @computed get selectedDocumentView() { if (SelectionManager.Views().length) return SelectionManager.Views()[0]; @@ -126,13 +130,13 @@ export class PropertiesView extends React.Component { return [CollectionViewType.Stacking, CollectionViewType.NoteTaking].includes(this.selectedDoc?.type_collection as any); } - rtfWidth = () => (!this.selectedDoc ? 0 : Math.min(NumCast(this.selectedDoc?._width), this.props.width - 20)); - rtfHeight = () => (!this.selectedDoc ? 0 : this.rtfWidth() <= NumCast(this.selectedDoc?._width) ? Math.min(NumCast(this.selectedDoc?._height), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT); + rtfWidth = () => (!this.selectedLayoutDoc ? 0 : Math.min(NumCast(this.selectedLayoutDoc?._width), this.props.width - 20)); + rtfHeight = () => (!this.selectedLayoutDoc ? 0 : this.rtfWidth() <= NumCast(this.selectedLayoutDoc?._width) ? Math.min(NumCast(this.selectedLayoutDoc?._height), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT); @action docWidth = () => { - if (this.selectedDoc) { - const layoutDoc = this.selectedDoc; + const layoutDoc = this.selectedLayoutDoc; + if (layoutDoc) { const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._layout_fitWidth); if (aspect) return Math.min(NumCast(layoutDoc._width), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20)); return Doc.NativeWidth(layoutDoc) ? Math.min(NumCast(layoutDoc._width), this.props.width - 20) : this.props.width - 20; @@ -142,8 +146,8 @@ export class PropertiesView extends React.Component { @action docHeight = () => { - if (this.selectedDoc && this.dataDoc) { - const layoutDoc = this.selectedDoc; + const layoutDoc = this.selectedLayoutDoc; + if (layoutDoc && this.dataDoc) { return Math.max( 70, Math.min( @@ -288,7 +292,7 @@ export class PropertiesView extends React.Component { return (
{ */ @undoBatch changePermissions = (e: any, user: string) => { - const docs = (SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(dv => dv.props.Document)).filter(doc => doc).map(doc => (this.layoutDocAcls ? doc! : DocCast(doc)[DocData])); + const docs = SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(dv => (this.layoutDocAcls ? dv.layoutDoc : dv.dataDoc)); SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs, this.layoutDocAcls); }; @@ -453,7 +457,7 @@ export class PropertiesView extends React.Component { const individualTableEntries = []; const usersAdded: string[] = []; // all shared users being added - organized by denormalized email - const seldoc = this.layoutDocAcls || !this.selectedDoc ? this.selectedDoc : Doc.GetProto(this.selectedDoc); + const seldoc = this.layoutDocAcls ? this.selectedLayoutDoc : this.selectedDoc?.[DocData]; // adds each user to usersAdded SharingManager.Instance.users.forEach(eachUser => { var userOnDoc = true; @@ -630,10 +634,11 @@ export class PropertiesView extends React.Component { @action rotate = (angle: number) => { const _centerPoints: { X: number; Y: number }[] = []; - if (this.selectedDoc) { - const doc = this.selectedDoc; - if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) { - const ink = Cast(doc.data, InkField)?.inkData; + const doc = this.selectedDoc; + const layout = this.selectedLayoutDoc; + if (doc && layout) { + if (doc.type === DocumentType.INK && doc.x && doc.y && layout._width && layout._height && doc.data) { + const ink = Cast(doc.stroke, InkField)?.inkData; if (ink) { const xs = ink.map(p => p.X); const ys = ink.map(p => p.Y); @@ -646,9 +651,9 @@ export class PropertiesView extends React.Component { } var index = 0; - if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) { - doc.rotation = NumCast(doc.rotation) + angle; - const inks = Cast(doc.data, InkField)?.inkData; + if (doc.type === DocumentType.INK && doc.x && doc.y && layout._width && layout._height && doc.data) { + layout.rotation = NumCast(layout.rotation) + angle; + const inks = Cast(doc.stroke, InkField)?.inkData; if (inks) { const newPoints: { X: number; Y: number }[] = []; inks.forEach(ink => { @@ -656,7 +661,7 @@ export class PropertiesView extends React.Component { const newY = Math.sin(angle) * (ink.X - _centerPoints[index].X) + Math.cos(angle) * (ink.Y - _centerPoints[index].Y) + _centerPoints[index].Y; newPoints.push({ X: newX, Y: newY }); }); - doc.data = new InkField(newPoints); + doc.stroke = new InkField(newPoints); const xs = newPoints.map(p => p.X); const ys = newPoints.map(p => p.Y); const left = Math.min(...xs); @@ -664,8 +669,8 @@ export class PropertiesView extends React.Component { const right = Math.max(...xs); const bottom = Math.max(...ys); - doc._height = bottom - top; - doc._width = right - left; + layout._height = bottom - top; + layout._width = right - left; } index++; } @@ -1178,7 +1183,7 @@ export class PropertiesView extends React.Component { return ( <> (this.openAppearance = bool)} onDoubleClick={() => this.CloseAll()}> - {this.selectedDoc?.layout_isSvg ? this.appearanceEditor : null} + {this.selectedLayoutDoc?.layout_isSvg ? this.appearanceEditor : null} (this.openTransform = bool)} onDoubleClick={() => this.CloseAll()}> {this.transformEditor} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 2162d8878..5399d38b4 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -122,7 +122,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt, props: Opt, props: Opt(docs); } else { - Doc.SetInPlace(this.rootDoc, 'dockingConfig', json, true); - Doc.SetInPlace(this.rootDoc, 'data', new List(docs), true); + Doc.SetInPlace(this.Document, 'dockingConfig', json, true); + Doc.SetInPlace(this.Document, 'data', new List(docs), true); } } this._flush?.end(); @@ -479,9 +479,9 @@ export class CollectionDockingView extends CollectionSubView() { tabDestroyed = (tab: any) => { this._flush = this._flush ?? UndoManager.StartBatch('tab movement'); if (tab.DashDoc && ![DocumentType.PRES].includes(tab.DashDoc?.type) && !tab.contentItem.config.props.keyValue) { - Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc, undefined, undefined, true); // if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed - if (tab.DashDoc.embedContainer === this.rootDoc) tab.DashDoc.embedContainer = undefined; + if (tab.DashDoc.embedContainer === this.Document) tab.DashDoc.embedContainer = undefined; if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true); Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc); } @@ -512,28 +512,31 @@ export class CollectionDockingView extends CollectionSubView() { _layout_fitWidth: true, title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, }); - Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd); - inheritParentAcls(this.rootDoc, docToAdd, false); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd, undefined, undefined, true); + inheritParentAcls(this.Document, docToAdd, false); CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); } }); - let addNewDoc = action(() => { - const dashboard = Doc.ActiveDashboard; - if (dashboard) { - dashboard['pane-count'] = NumCast(dashboard['pane-count']) + 1; - const docToAdd = Docs.Create.FreeformDocument([], { - _width: this.props.PanelWidth(), - _height: this.props.PanelHeight(), - _layout_fitWidth: true, - _freeform_backgroundGrid: true, - title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, - }); - Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd); - inheritParentAcls(this.dataDoc, docToAdd, false); - CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); - } - }); + let addNewDoc = undoable( + action(() => { + const dashboard = Doc.ActiveDashboard; + if (dashboard) { + dashboard['pane-count'] = NumCast(dashboard['pane-count']) + 1; + const docToAdd = Docs.Create.FreeformDocument([], { + _width: this.props.PanelWidth(), + _height: this.props.PanelHeight(), + _layout_fitWidth: true, + _freeform_backgroundGrid: true, + title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, + }); + Doc.AddDocToList(Doc.MyHeaderBar, 'data', docToAdd, undefined, undefined, true); + inheritParentAcls(this.dataDoc, docToAdd, false); + CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); + } + }), + 'add new tab' + ); stack.header?.controlsContainer .find('.lm_close') //get the close icon @@ -569,7 +572,7 @@ export class CollectionDockingView extends CollectionSubView() { }; render() { - const href = ImageCast(this.rootDoc.thumb)?.url?.href; + const href = ImageCast(this.Document.thumb)?.url?.href; return this.props.renderDepth > -1 ? (
{href ? ( diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index b190eb23d..3c555e731 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -1,43 +1,26 @@ import React = require('react'); -import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon, FontAwesomeIconProps } from '@fortawesome/react-fontawesome'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, Lambda, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { ColorState } from 'react-color'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; -import { Document } from '../../../fields/documentSchemas'; -import { Id } from '../../../fields/FieldSymbols'; -import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { RichTextField } from '../../../fields/RichTextField'; -import { listSpec } from '../../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; -import { GestureUtils } from '../../../pen-gestures/GestureUtils'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils'; -import { Docs } from '../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; -import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { AntimodeMenu } from '../AntimodeMenu'; import { EditableView } from '../EditableView'; -import { GestureOverlay } from '../GestureOverlay'; -import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from '../InkingStroke'; -import { LightboxView } from '../LightboxView'; import { MainView } from '../MainView'; -import { media_state } from '../nodes/AudioBox'; -import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; -import { DocumentView, DocumentViewInternal, OpenWhereMod } from '../nodes/DocumentView'; -import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; +import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; -import { CollectionDockingView } from './CollectionDockingView'; -import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionLinearView } from './collectionLinear'; import './CollectionMenu.scss'; @@ -66,7 +49,7 @@ export class CollectionMenu extends AntimodeMenu { componentDidMount() { reaction( - () => SelectionManager.Views().length && SelectionManager.Views()[0], + () => SelectionManager.Views().lastElement(), view => view && this.SetSelection(view) ); } @@ -174,7 +157,6 @@ export class CollectionMenu extends AntimodeMenu {
); - // NEW BUTTONS //dash col linear view buttons const contMenuButtons = (
{ ); return contMenuButtons; - - // const button = Pin Menu
} key="pin menu" placement="bottom"> - // - // ; - - // //OLD BUTTONS - // return this.getElement(!this.SelectedCollection ? [/*button*/] : - // [, - // prop, - // /*button*/]); } } @@ -228,7 +195,7 @@ export class CollectionViewBaseChrome extends React.Component { let formatStr = source.length && Cast(source[0].text, RichTextField, null)?.Text; try { @@ -250,24 +217,24 @@ export class CollectionViewBaseChrome extends React.Component source.length && (this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]))), initialize: emptyFunction, }; _contentCommand = { params: ['target', 'source'], title: 'set content', - script: 'getProto(self.target).data = copyField(self.source);', + script: 'getProto(this.target).data = copyField(this.source);', immediate: undoBatch((source: Doc[]) => (Doc.GetProto(this.target).data = new List(source))), initialize: emptyFunction, }; _onClickCommand = { params: ['target', 'proxy'], title: 'copy onClick', - script: `{ if (self.proxy?.[0]) { - getProto(self.proxy[0]).onClick = copyField(self.target.onClick); - getProto(self.proxy[0]).target = self.target.target; - getProto(self.proxy[0]).source = copyField(self.target.source); + script: `{ if (this.proxy?.[0]) { + getProto(this.proxy[0]).onClick = copyField(this.target.onClick); + getProto(this.proxy[0]).target = this.target.target; + getProto(this.proxy[0]).source = copyField(this.target.source); }}`, immediate: undoBatch((source: Doc[]) => {}), initialize: emptyFunction, @@ -275,7 +242,7 @@ export class CollectionViewBaseChrome extends React.Component { this.target._freeform_panX = 0; this.target._freeform_panY = 0; @@ -292,22 +259,22 @@ export class CollectionViewBaseChrome extends React.Component (this.target._freeform_fitContentsToBox = !this.target._freeform_fitContentsToBox)), initialize: emptyFunction, }; _fitContentCommand = { params: ['target'], title: 'toggle clusters', - script: 'self.target._freeform_useClusters = !self.target._freeform_useClusters;', + script: 'this.target._freeform_useClusters = !this.target._freeform_useClusters;', immediate: undoBatch((source: Doc[]) => (this.target._freeform_useClusters = !this.target._freeform_useClusters)), initialize: emptyFunction, }; _saveFilterCommand = { params: ['target'], title: 'save filter', - script: `self.target._childFilters = compareLists(self['target-childFilters'],self.target._childFilters) ? undefined : copyField(self['target-childFilters']); - self.target._searchFilterDocs = compareLists(self['target-searchFilterDocs'],self.target._searchFilterDocs) ? undefined: copyField(self['target-searchFilterDocs']);`, + script: `this.target._childFilters = compareLists(this['target-childFilters'],this.target._childFilters) ? undefined : copyField(this['target-childFilters']); + this.target._searchFilterDocs = compareLists(this['target-searchFilterDocs'],this.target._searchFilterDocs) ? undefined: copyField(this['target-searchFilterDocs']);`, immediate: undoBatch((source: Doc[]) => { this.target._childFilters = undefined; this.target._searchFilterDocs = undefined; @@ -390,57 +357,6 @@ export class CollectionViewBaseChrome extends React.Component; - case CollectionViewType.Stacking: - return ; - case CollectionViewType.NoteTaking: - return ; - case CollectionViewType.Schema: - return ; - case CollectionViewType.Tree: - return ; - case CollectionViewType.Masonry: - return ; - case CollectionViewType.Carousel: - case CollectionViewType.Carousel3D: - return ; - case CollectionViewType.Grid: - return ; - case CollectionViewType.Docking: - return ; - } - } - - @computed get otherSubChrome() { - const docType = this.props.docView.Document.type; - switch (docType) { - default: - return null; - case DocumentType.IMG: - return ; - case DocumentType.PDF: - return ; - case DocumentType.INK: - return ; - case DocumentType.WEB: - return ; - case DocumentType.VID: - return ; - case DocumentType.RTF: - return ; - case DocumentType.MAP: - return ; - } - } - private dropDisposer?: DragManager.DragDropDisposer; protected createDropTarget = (ele: HTMLDivElement) => { this.dropDisposer?.(); @@ -517,593 +433,11 @@ export class CollectionViewBaseChrome extends React.Component ); } - - @computed get viewModes() { - const excludedViewTypes = [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.StackedTimeline, CollectionViewType.Linear]; - const isPres: boolean = this.document && this.document.type === DocumentType.PRES; - return isPres ? null : ( -
- drop document to apply or drag to create button
} placement="bottom"> -
- - -
- -
- ); - } - - @computed get selectedDocumentView() { - return SelectionManager.Views().lastElement(); - } - @computed get selectedDoc() { - return SelectionManager.Docs().lastElement(); - } - @computed get notACollection() { - if (this.selectedDoc) { - const layoutField = Doc.LayoutField(this.selectedDoc); - return this.props.type === CollectionViewType.Docking || (typeof layoutField === 'string' && !layoutField?.includes('CollectionView')); - } else return false; - } - - @undoBatch - @action - startRecording = () => { - const doc = Docs.Create.ScreenshotDocument({ title: 'screen recording', _layout_fitWidth: true, _width: 400, _height: 200, mediaState: media_state.PendingRecording }); - CollectionDockingView.AddSplit(doc, OpenWhereMod.right); - }; - - @computed - get recordButton() { - const targetDoc = this.selectedDoc; - return ( - {'Capture screen'}
} placement="top"> - - - ); - } - - @undoBatch - onEmbed = () => { - if (this.selectedDoc && this.selectedDocumentView) { - // const copy = Doc.MakeCopy(this.selectedDocumentView.props.Document, true); - // copy.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width); - // copy.y = NumCast(this.selectedDoc.y) + 30; - // this.selectedDocumentView.props.addDocument?.(copy); - const embedding = Doc.MakeEmbedding(this.selectedDoc); - embedding.x = NumCast(this.selectedDoc.x) + NumCast(this.selectedDoc._width); - embedding.y = NumCast(this.selectedDoc.y) + 30; - this.selectedDocumentView.props.addDocument?.(embedding); - } - }; - onEmbedButtonDown = (e: React.PointerEvent): void => { - setupMoveUpEvents(this, e, this.onEmbedButtonMoved, emptyFunction, emptyFunction); - }; - - @undoBatch - onEmbedButtonMoved = (e: PointerEvent) => { - const contentDiv = this.selectedDocumentView?.ContentDiv; - if (contentDiv && this.selectedDoc) { - const dragData = new DragManager.DocumentDragData([this.selectedDoc]); - const offset = [e.clientX - contentDiv.getBoundingClientRect().x, e.clientY - contentDiv.getBoundingClientRect().y]; - dragData.defaultDropAction = 'embed'; - dragData.canEmbed = true; - DragManager.StartDocumentDrag([contentDiv], dragData, e.clientX, e.clientY, { - offsetX: offset[0], - offsetY: offset[1], - hideSource: false, - }); - return true; - } - return false; - }; - - @computed - get embedButton() { - const targetDoc = this.selectedDoc; - return !targetDoc || targetDoc.type === DocumentType.PRES ? null : ( - {'Tap or Drag to create an embedding'}
} placement="top"> - - - ); - } - - @computed get lightboxButton() { - const targetDoc = this.selectedDoc; - return !targetDoc ? null : ( - {'View in Lightbox'}
} placement="top"> - - - ); - } - - @computed get toggleOverlayButton() { - return ( - <> - Toggle Overlay Layer
} placement="bottom"> - - - - ); - } - render() { return (
-
- {this.notACollection || this.props.type === CollectionViewType.Invalid ? null : this.viewModes} -
- {this.embedButton} - {/* {this.pinButton} */} - {this.toggleOverlayButton} -
- {this.subChrome} -
- {this.lightboxButton} - {this.recordButton} - {!this._buttonizableCommands ? null : this.templateChrome} -
-
-
- ); - } -} - -@observer -export class CollectionDockingChrome extends React.Component { - render() { - return null; - } -} - -@observer -export class CollectionFreeFormViewChrome extends React.Component { - public static Instance: CollectionFreeFormViewChrome; - constructor(props: any) { - super(props); - CollectionFreeFormViewChrome.Instance = this; - } - get document() { - return this.props.docView.props.Document; - } - @computed get dataField() { - return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? '_annotations' : '')]; - } - @computed get childDocs() { - return DocListCast(this.dataField); - } - @computed get selectedDocumentView() { - return SelectionManager.Views().lastElement(); - } - @computed get selectedDoc() { - return SelectionManager.Docs().lastElement(); - } - @computed get isText() { - return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false; - } - - public static gotoKeyFrame(doc: Doc, newFrame: number) { - if (doc) { - const childDocs = DocListCast(doc[Doc.LayoutFieldKey(doc)]); - const currentFrame = Cast(doc._currentFrame, 'number', null); - if (currentFrame === undefined) { - doc._currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0); - } - CollectionFreeFormView.updateKeyframe(undefined, [...childDocs, doc], currentFrame || 0); - doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame); - } - } - - _keyTimer: NodeJS.Timeout | undefined; - @undoBatch - @action - nextKeyframe = (): void => { - const currentFrame = Cast(this.document._currentFrame, 'number', null); - if (currentFrame === undefined) { - this.document._currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); - } - this._keyTimer = CollectionFreeFormView.updateKeyframe(this._keyTimer, [...this.childDocs, this.document], currentFrame || 0); - this.document._currentFrame = Math.max(0, (currentFrame || 0) + 1); - this.document.lastFrame = Math.max(NumCast(this.document._currentFrame), NumCast(this.document.lastFrame)); - }; - @undoBatch - @action - prevKeyframe = (): void => { - const currentFrame = Cast(this.document._currentFrame, 'number', null); - if (currentFrame === undefined) { - this.document._currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); - } - this._keyTimer = CollectionFreeFormView.gotoKeyframe(this._keyTimer, [...this.childDocs, this.document], 1000); - this.document._currentFrame = Math.max(0, (currentFrame || 0) - 1); - }; - - private _palette = ['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '']; - private _width = ['1', '5', '10', '100']; - private _dotsize = [10, 20, 30, 40]; - private _draw = ['∿', '=', '⎯', '→', '↔︎', 'ロ', 'O']; - private _head = ['', '', '', '', 'arrow', '', '']; - private _end = ['', '', '', 'arrow', 'arrow', '', '']; - private _shapePrims = ['', '', 'line', 'line', 'line', 'rectangle', 'circle'] as GestureUtils.Gestures[]; - private _title = ['pen', 'highlighter', 'line', 'line with arrow', 'line with double arrows', 'square', 'circle']; - private _faName = ['pen-fancy', 'highlighter', 'minus', 'long-arrow-alt-right', 'arrows-alt-h', 'square', 'circle']; - @observable _selectedPrimitive = this._shapePrims.length; - @observable _keepPrimitiveMode = false; // for whether primitive selection enters a one-shot or persistent mode - @observable _colorBtn = false; - @observable _widthBtn = false; - @observable _fillBtn = false; - - @action clearKeepPrimitiveMode() { - this._selectedPrimitive = this._shapePrims.length; - } - @action primCreated() { - if (!this._keepPrimitiveMode) { - //get out of ink mode after each stroke= - if (Doc.ActiveTool === InkTool.Highlighter && GestureOverlay.Instance.SavedColor) SetActiveInkColor(GestureOverlay.Instance.SavedColor); - Doc.ActiveTool = InkTool.None; - this._selectedPrimitive = this._shapePrims.length; - SetActiveArrowStart('none'); - SetActiveArrowEnd('none'); - } - } - - @action - changeColor = (color: string, type: string) => { - const col: ColorState = { - hex: color, - hsl: { a: 0, h: 0, s: 0, l: 0, source: '' }, - hsv: { a: 0, h: 0, s: 0, v: 0, source: '' }, - rgb: { a: 0, r: 0, b: 0, g: 0, source: '' }, - oldHue: 0, - source: '', - }; - if (type === 'color') { - SetActiveInkColor(Utils.colorString(col)); - } else if (type === 'fill') { - SetActiveFillColor(Utils.colorString(col)); - } - }; - - @action - editProperties = (value: any, field: string) => { - SelectionManager.Views().forEach( - action((element: DocumentView) => { - const doc = Document(element.rootDoc); - if (doc.type === DocumentType.INK) { - switch (field) { - case 'width': - doc.stroke_width = Number(value); - break; - case 'color': - doc.color = String(value); - break; - case 'fill': - doc.fillColor = String(value); - break; - case 'dash': - doc.stroke_dash = value; - } - } - }) - ); - }; - - @computed get drawButtons() { - const func = action((e: React.MouseEvent | React.PointerEvent, i: number, keep: boolean) => { - this._keepPrimitiveMode = keep; - // these are for shapes - if (this._selectedPrimitive !== i) { - this._selectedPrimitive = i; - if (this._title[i] === 'highlighter') { - Doc.ActiveTool = InkTool.Highlighter; - GestureOverlay.Instance.SavedColor = ActiveInkColor(); - SetActiveInkColor('rgba(245, 230, 95, 0.75)'); - } else { - Doc.ActiveTool = InkTool.Pen; - } - SetActiveArrowStart(this._head[i]); - SetActiveArrowEnd(this._end[i]); - SetActiveBezierApprox('300'); - - if (GestureOverlay.Instance) GestureOverlay.Instance.InkShape = this._shapePrims[i]; - } else { - this._selectedPrimitive = this._shapePrims.length; - Doc.ActiveTool = InkTool.None; - SetActiveArrowStart(''); - SetActiveArrowEnd(''); - if (GestureOverlay.Instance) GestureOverlay.Instance.InkShape = undefined; - SetActiveBezierApprox('0'); - } - e.stopPropagation(); - }); - return ( -
- {this._draw.map((icon, i) => ( - {this._title[i]}
} placement="bottom"> - - - ))} -
- ); - } - - toggleButton = (key: string, value: boolean, setter: () => {}, icon: FontAwesomeIconProps['icon'], ele: JSX.Element | null) => { - return ( - {key}
} placement="bottom"> - - - ); - }; - - @computed get widthPicker() { - const widthPicker = this.toggleButton('stroke width', this._widthBtn, () => (this._widthBtn = !this._widthBtn), 'bars', null); - return !this._widthBtn ? ( - widthPicker - ) : ( -
- {widthPicker} - {this._width.map((wid, i) => ( - change width
} placement="bottom"> - - - ))} -
- ); - } - - @computed get colorPicker() { - const colorPicker = this.toggleButton('stroke color', this._colorBtn, () => (this._colorBtn = !this._colorBtn), 'pen-nib',
); - return !this._colorBtn ? ( - colorPicker - ) : ( -
- {colorPicker} - {this._palette.map(color => ( - - ))} -
- ); - } - @computed get fillPicker() { - const fillPicker = this.toggleButton('shape fill color', this._fillBtn, () => (this._fillBtn = !this._fillBtn), 'fill-drip',
); - return !this._fillBtn ? ( - fillPicker - ) : ( -
- {fillPicker} - {this._palette.map(color => ( - - ))} -
- ); - } - - render() { - return !this.props.docView.layoutDoc ? null : ( -
- - {!this.isText ? ( - <> - {this.drawButtons} - {this.widthPicker} - {this.colorPicker} - {this.fillPicker} - {Doc.noviceMode || this.props.isDoc ? null : ( - <> - Back Frame
} placement="bottom"> -
- -
- - Frame number
} placement="bottom"> -
this.props.docView.ComponentView?.setKeyFrameEditing?.(!this.props.docView.ComponentView?.getKeyFrameEditing?.()))}> - {NumCast(this.document._currentFrame)} -
- - Forward Frame
} placement="bottom"> -
- -
- - - )} - - ) : null} - {!this.selectedDocumentView?.ComponentView?.menuControls ? null : this.selectedDocumentView?.ComponentView?.menuControls?.()} -
- ); - } -} -@observer -export class CollectionStackingViewChrome extends React.Component { - @observable private _currentKey: string = ''; - @observable private suggestions: string[] = []; - - get document() { - return this.props.docView.props.Document; - } - - @computed private get descending() { - return StrCast(this.document._columnsSort) === 'descending'; - } - @computed get pivotField() { - return StrCast(this.document._pivotField); - } - - getKeySuggestions = async (value: string): Promise => { - const val = value.toLowerCase(); - const docs = DocListCast(this.document[this.props.fieldKey]); - - if (Doc.noviceMode) { - if (docs instanceof Doc) { - const keys = Object.keys(docs).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('author_date') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_')); - return keys.filter(key => key.toLowerCase().indexOf(val) > -1); - } - const keys = new Set(); - docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); - const noviceKeys = Array.from(keys).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('author_date') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_')); - return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1); - } - - if (docs instanceof Doc) { - return Object.keys(docs).filter(key => key.toLowerCase().indexOf(val) > -1); - } else { - const keys = new Set(); - docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); - return Array.from(keys).filter(key => key.toLowerCase().indexOf(val) > -1); - } - }; - - @action - onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => { - this._currentKey = newValue; - }; - - getSuggestionValue = (suggestion: string) => suggestion; - - renderSuggestion = (suggestion: string) => { - return

{suggestion}

; - }; - - onSuggestionFetch = async ({ value }: { value: string }) => { - const sugg = await this.getKeySuggestions(value); - runInAction(() => { - this.suggestions = sugg; - }); - }; - - @action - onSuggestionClear = () => { - this.suggestions = []; - }; - - @action - setValue = (value: string) => { - this.document._pivotField = value; - return true; - }; - - @action toggleSort = () => { - this.document._columnsSort = this.document._columnsSort === 'descending' ? 'ascending' : this.document._columnsSort === 'ascending' ? undefined : 'descending'; - }; - @action resetValue = () => { - this._currentKey = this.pivotField; - }; - - render() { - const doctype = this.props.docView.Document.type; - const isPres: boolean = doctype === DocumentType.PRES; - return isPres ? null : ( -
-
-
GROUP BY:
-
- -
-
- this.pivotField} - autosuggestProps={{ - resetValue: this.resetValue, - value: this._currentKey, - onChange: this.onKeyChange, - autosuggestProps: { - inputProps: { - value: this._currentKey, - onChange: this.onKeyChange, - }, - getSuggestionValue: this.getSuggestionValue, - suggestions: this.suggestions, - alwaysRenderSuggestions: true, - renderSuggestion: this.renderSuggestion, - onSuggestionsFetchRequested: this.onSuggestionFetch, - onSuggestionsClearRequested: this.onSuggestionClear, - }, - }} - oneLine - SetValue={this.setValue} - contents={this.pivotField ? this.pivotField : 'N/A'} - /> -
+
{!this._buttonizableCommands ? null : this.templateChrome}
); @@ -1230,123 +564,6 @@ export class CollectionNoteTakingViewChrome extends React.Component { - // private _textwrapAllRows: boolean = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []).length > 0; - get document() { - return this.props.docView.props.Document; - } - - @undoBatch - togglePreview = () => { - const dividerWidth = 4; - const borderWidth = 0; - const panelWidth = this.props.docView.props.PanelWidth(); - const previewWidth = NumCast(this.document.schema_previewWidth); - const tableWidth = panelWidth - 2 * borderWidth - dividerWidth - previewWidth; - this.document.schema_previewWidth = previewWidth === 0 ? Math.min(tableWidth / 3, 200) : 0; - }; - - @undoBatch - @action - toggleTextwrap = async () => { - const textwrappedRows = Cast(this.document.textwrappedSchemaRows, listSpec('string'), []); - if (textwrappedRows.length) { - this.document.textwrappedSchemaRows = new List([]); - } else { - const docs = DocListCast(this.document[this.props.fieldKey]); - const allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]); - this.document.textwrappedSchemaRows = new List(allRows); - } - }; - - render() { - const previewWidth = NumCast(this.document.schema_previewWidth); - const textWrapped = Cast(this.document.textwrappedSchemaRows, listSpec('string'), []).length > 0; - - return ( -
-
-
Show Preview:
-
-
{previewWidth !== 0 ? 'on' : 'off'}
-
-
-
- ); - } -} - -@observer -export class CollectionTreeViewChrome extends React.Component { - get document() { - return this.props.docView.props.Document; - } - get sortAscending() { - return this.document[this.props.fieldKey + '-sortAscending']; - } - set sortAscending(value) { - this.document[this.props.fieldKey + '-sortAscending'] = value; - } - @computed private get ascending() { - return Cast(this.sortAscending, 'boolean', null); - } - - @action toggleSort = () => { - if (this.sortAscending) this.sortAscending = undefined; - else if (this.sortAscending === undefined) this.sortAscending = false; - else this.sortAscending = true; - }; - - render() { - return ( -
- -
- ); - } -} - -// Enter scroll speed for 3D Carousel -@observer -export class Collection3DCarouselViewChrome extends React.Component { - get document() { - return this.props.docView.props.Document; - } - @computed get scrollSpeed() { - return this.document._autoScrollSpeed; - } - - @action - setValue = (value: string) => { - const numValue = Number(StrCast(value)); - if (numValue > 0) { - this.document._autoScrollSpeed = numValue; - return true; - } - return false; - }; - - render() { - return ( -
-
- {/* {FormattedTextBox.Focused ? : null} */} -
AUTOSCROLL SPEED:
-
- StrCast(this.scrollSpeed)} oneLine SetValue={this.setValue} contents={this.scrollSpeed ? this.scrollSpeed : 1000} /> -
-
-
- ); - } -} - /** * Chrome for grid view. */ @@ -1492,12 +709,6 @@ export class CollectionGridViewChrome extends React.Component - {/* - - - - ) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} /> - */} @@ -1526,6 +737,3 @@ export class CollectionGridViewChrome extends React.Component (dref = r || undefined)} Document={doc} - pointerEvents={this.blockPointerEventsWhenDragging} DataDoc={dataDoc ?? (!Doc.AreProtosEqual(doc[DocData], doc) ? doc[DocData] : undefined)} + pointerEvents={this.blockPointerEventsWhenDragging} renderDepth={this.props.renderDepth + 1} PanelWidth={width} PanelHeight={height} @@ -635,7 +635,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { key="notes" style={{ overflowY: this.props.isContentActive() ? 'auto' : 'hidden', - background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor), + background: this.props.styleProvider?.(this.Document, this.props, StyleProp.BackgroundColor), pointerEvents: this.backgroundEvents, }} onScroll={action(e => (this._scroll = e.currentTarget.scrollTop))} diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index abb12a8ab..ad8144466 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -43,7 +43,7 @@ export class CollectionPileView extends CollectionSubView() { removePileDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { (doc instanceof Doc ? [doc] : doc).forEach(d => Doc.deiconifyView(d)); const ret = this.props.moveDocument?.(doc, targetCollection, addDoc) || false; - if (ret && !DocListCast(this.rootDoc[this.fieldKey ?? 'data']).length) this.props.DocumentView?.().props.removeDocument?.(this.rootDoc); + if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this.props.DocumentView?.().props.removeDocument?.(this.Document); return ret; }; @@ -78,12 +78,12 @@ export class CollectionPileView extends CollectionSubView() { toggleStarburst = action(() => { this.layoutDoc._freeform_scale = undefined; if (this.layoutEngine() === computeStarburstLayout.name) { - if (NumCast(this.rootDoc._width) !== NumCast(this.rootDoc._starburstDiameter, 500)) { - this.rootDoc._starburstDiameter = NumCast(this.rootDoc._width); + if (NumCast(this.layoutDoc._width) !== NumCast(this.Document._starburstDiameter, 500)) { + this.Document._starburstDiameter = NumCast(this.layoutDoc._width); } const defaultSize = 110; - this.rootDoc.x = NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2; - this.rootDoc.y = NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2; + this.Document.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width) / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2; + this.Document.y = NumCast(this.Document.y) + NumCast(this.layoutDoc._height) / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2; this.layoutDoc._width = NumCast(this.layoutDoc._freeform_pileWidth, defaultSize); this.layoutDoc._height = NumCast(this.layoutDoc._freeform_pileHeight, defaultSize); DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false); @@ -91,9 +91,9 @@ export class CollectionPileView extends CollectionSubView() { this.layoutDoc._freeform_panY = -10; this.props.Document._freeform_pileEngine = computePassLayout.name; } else { - const defaultSize = NumCast(this.rootDoc._starburstDiameter, 400); - this.rootDoc.x = NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) / 2 - defaultSize / 2; - this.rootDoc.y = NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) / 2 - defaultSize / 2; + const defaultSize = NumCast(this.Document._starburstDiameter, 400); + this.Document.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width) / 2 - defaultSize / 2; + this.Document.y = NumCast(this.Document.y) + NumCast(this.layoutDoc._height) / 2 - defaultSize / 2; this.layoutDoc._freeform_pileWidth = NumCast(this.layoutDoc._width); this.layoutDoc._freeform_pileHeight = NumCast(this.layoutDoc._height); this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0; diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 3351ca48e..7bde2cb5f 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -192,7 +192,7 @@ export class CollectionStackedTimeline extends CollectionSubView 15 && !this.IsTrimming) { - const anchor = CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this._markerStart, this._markerEnd, undefined, true); + const anchor = CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.props.fieldKey, this._markerStart, this._markerEnd, undefined, true); setTimeout(() => DocumentManager.Instance.getDocumentView(anchor)?.select(false)); } (!isClick || !wasSelecting) && (this._markerEnd = undefined); @@ -274,7 +274,7 @@ export class CollectionStackedTimeline extends CollectionSubView { if (shiftKey) { - CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.props.fieldKey, this.currentTime, undefined, undefined, true); + CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.props.fieldKey, this.currentTime, undefined, undefined, true); } else { !wasPlaying && this.props.setTime(this.toTimeline(clientX - rect.x, rect.width)); } @@ -388,8 +388,8 @@ export class CollectionStackedTimeline extends CollectionSubView, anchorEndTime: Opt, docAnchor: Opt, addAsAnnotation: boolean) { - if (anchorStartTime === undefined) return rootDoc; + static createAnchor(doc: Doc, dataDoc: Doc, fieldKey: string, anchorStartTime: Opt, anchorEndTime: Opt, docAnchor: Opt, addAsAnnotation: boolean) { + if (anchorStartTime === undefined) return doc; const startTag = '_timecodeToShow'; const endTag = '_timecodeToHide'; const anchor = @@ -402,7 +402,7 @@ export class CollectionStackedTimeline extends CollectionSubView e.stopPropagation()} + onWheel={e => this.isContentActive() && e.stopPropagation()} onScroll={this.setScroll} onMouseMove={e => this.isContentActive() && this.onHover(e)} ref={wrapper => (this._timelineWrapper = wrapper)}> @@ -775,7 +775,7 @@ class StackedTimelineAnchor extends React.Component // context menu contextMenuItems = () => { const resetTitle = { - script: ScriptField.MakeFunction(`self.title = self["${this.props.endTag}"] ? "#" + formatToTime(self["${this.props.startTag}"]) + "-" + formatToTime(self["${this.props.endTag}"]) : "#" + formatToTime(self["${this.props.startTag}"])`)!, + script: ScriptField.MakeFunction(`this.title = this["${this.props.endTag}"] ? "#" + formatToTime(this["${this.props.startTag}"]) + "-" + formatToTime(this["${this.props.endTag}"]) : "#" + formatToTime(this["${this.props.startTag}"])`)!, icon: 'folder-plus', label: 'Reset Title', }; diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index dddb3ec71..165ccbdb1 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -142,7 +142,7 @@ transform-origin: top left; grid-column-end: span 1; height: 100%; - margin: auto; + //margin: auto; display: inline-grid; } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index da00093dd..5b86aaf86 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -9,7 +9,7 @@ import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; import { emptyFunction, returnEmptyDoclist, returnFalse, returnNone, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -309,12 +309,14 @@ export class CollectionStackingView extends CollectionSubView (this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined); @observable docRefs = new ObservableMap(); + childFitWidth = (doc: Doc) => Cast(this.Document.childLayoutFitWidth, 'boolean', this.props.childLayoutFitWidth?.(doc) ?? Cast(doc.layout_fitWidth, 'boolean', null)); // this is what renders the document that you see on the screen // called in Children: this actually adds a document to our children list getDisplayDoc(doc: Doc, width: () => number, count: number) { const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField ? undefined : this.props.DataDoc; const height = () => this.getDocHeight(doc); - + const panelHeight = () => (this.isStackingView ? height() : Math.min(height(), this.props.PanelHeight())); + const panelWidth = () => (this.isStackingView ? width() : this.columnWidth); const stackedDocTransform = () => this.getDocTransform(doc); this._docXfs.push({ stackedDocTransform, width, height }); return count > this._renderCount ? null : ( @@ -323,21 +325,21 @@ export class CollectionStackingView extends CollectionSubView (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1)); - const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? NumCast(d._width) : 0); - const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? NumCast(d._height) : 0); + const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!this.childFitWidth(childLayoutDoc) ? NumCast(d._width) : 0); + const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!this.childFitWidth(childLayoutDoc) ? NumCast(d._height) : 0); if (nw && nh) { const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid); return Math.min(maxHeight, (docWid * nh) / nw); } const childHeight = NumCast(childLayoutDoc._height); - const panelHeight = childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; + const panelHeight = this.childFitWidth(childLayoutDoc) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; return Math.min(childHeight, maxHeight, panelHeight); } @@ -664,41 +666,35 @@ export class CollectionStackingView extends CollectionSubView 35; @computed get buttonMenu() { - const menuDoc: Doc = Cast(this.rootDoc.layout_headerButton, Doc, null); - // TODO:glr Allow support for multiple buttons - if (menuDoc) { - const width: number = NumCast(menuDoc._width, 30); - const height: number = NumCast(menuDoc._height, 30); - return ( -
- -
- ); - } + const menuDoc = DocCast(this.layoutDoc.layout_headerButton); + return !menuDoc ? null : ( +
+ +
+ ); } @computed get nativeWidth() { @@ -723,8 +719,8 @@ export class CollectionStackingView extends CollectionSubView {buttonMenu || noviceExplainer ? ( @@ -739,7 +735,7 @@ export class CollectionStackingView extends CollectionSubView (this._scroll = e.currentTarget.scrollTop))} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 9626f06ca..8896e2d61 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -17,15 +17,14 @@ import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes' import { Networking } from '../../Network'; import { DragManager, dropActionType } from '../../util/DragManager'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; -import { InteractionUtils } from '../../util/InteractionUtils'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { DocComponent } from '../DocComponent'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; +import { LoadingBox } from '../nodes/LoadingBox'; import { CollectionView, CollectionViewProps } from './CollectionView'; import React = require('react'); -import { LoadingBox } from '../nodes/LoadingBox'; export interface SubCollectionViewProps extends CollectionViewProps { isAnyChildContentActive: () => boolean; @@ -60,7 +59,8 @@ export function CollectionSubView(moreProps?: X) { return this.props.DataDoc instanceof Doc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) : this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template } - rootSelected = () => this.props.isSelected() || (this.rootDoc && this.props.rootSelected()); + // this returns whether either the collection is selected, or the template that it is part of is selected + rootSelected = () => this.props.isSelected() || this.props.rootSelected(); // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc. // When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through @@ -100,7 +100,7 @@ export function CollectionSubView(moreProps?: X) { } else if (Cast(this.dataField, listSpec(Doc), null)) { // otherwise, if the collection data is a list, then use it. rawdocs = Cast(this.dataField, listSpec(Doc), null); - } else { + } else if (this.dataField) { // Finally, if it's not a doc or a list and the document is a template, we try to render the root doc. // For example, if an image doc is rendered with a slide template, the template will try to render the data field as a collection. // Since the data field is actually an image, we set the list of documents to the singleton of root document's proto which will be an image. @@ -217,18 +217,18 @@ export function CollectionSubView(moreProps?: X) { const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); if (movedDocs.length) { const canAdd = - (de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.rootDoc)) && (dropAction !== 'inSame' || docDragData.draggedDocuments.every(d => d.embedContainer === this.rootDoc)); - const moved = docDragData.moveDocument(movedDocs, this.rootDoc, canAdd ? this.addDocument : returnFalse); + (de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.Document)) && (dropAction !== 'inSame' || docDragData.draggedDocuments.every(d => d.embedContainer === this.Document)); + const moved = docDragData.moveDocument(movedDocs, this.Document, canAdd ? this.addDocument : returnFalse); added = canAdd || moved ? moved : undefined; } else if (addedDocs.length) { added = this.addDocument(addedDocs); } - if (!added && ScriptCast(this.rootDoc.dropConverter)) { - ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData }); + if (!added && ScriptCast(this.Document.dropConverter)) { + ScriptCast(this.Document.dropConverter)?.script.run({ dragData: docDragData }); added = addedDocs.length ? this.addDocument(addedDocs) : true; } } else { - ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData }); + ScriptCast(this.Document.dropConverter)?.script.run({ dragData: docDragData }); added = this.addDocument(docDragData.droppedDocuments); !added && alert('You cannot perform this move'); } @@ -238,7 +238,7 @@ export function CollectionSubView(moreProps?: X) { } else if (de.complete.annoDragData) { const dropCreator = de.complete.annoDragData.dropDocCreator; de.complete.annoDragData.dropDocCreator = () => { - const dropped = dropCreator(this.props.isAnnotationOverlay ? this.rootDoc : undefined); + const dropped = dropCreator(this.props.isAnnotationOverlay ? this.Document : undefined); this.addDocument(dropped); return dropped; }; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index a8f5345b7..1cdd200e5 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -47,9 +47,9 @@ export class CollectionTimeView extends CollectionSubView() { getAnchor = (addAsAnnotation: boolean) => { const anchor = Docs.Create.HTMLMarkerDocument([], { title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any, - annotationOn: this.rootDoc, + annotationOn: this.Document, }); - PresBox.pinDocView(anchor, { pinData: { type_collection: true, pivot: true, filters: true } }, this.rootDoc); + PresBox.pinDocView(anchor, { pinData: { type_collection: 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 diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 54332a7fd..b34598731 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -101,7 +101,7 @@ export class CollectionTreeView extends CollectionSubView this.rootDoc.layout_autoHeight, + () => this.layoutDoc.layout_autoHeight, auto => auto && this.computeHeight(), { fireImmediately: true } ); @@ -117,19 +117,19 @@ export class CollectionTreeView extends CollectionSubView { this.refList.delete(ref); - this.rootDoc.layout_autoHeight && this.computeHeight(); + this.layoutDoc.layout_autoHeight && this.computeHeight(); }; observeHeight = (ref: any) => { if (ref) { this.refList.add(ref); this.observer = new _global.ResizeObserver( action((entries: any) => { - if (this.rootDoc.layout_autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) { + if (this.layoutDoc.layout_autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) { this.computeHeight(); } }) ); - this.rootDoc.layout_autoHeight && this.computeHeight(); + this.layoutDoc.layout_autoHeight && this.computeHeight(); this.observer.observe(ref); } }; @@ -142,7 +142,7 @@ export class CollectionTreeView extends CollectionSubView sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d)); if (isAlreadyInTree() !== sameTree) { console.log('WHAAAT'); @@ -160,7 +160,7 @@ export class CollectionTreeView extends CollectionSubView !docs.includes(v)); - if ((doc instanceof Doc ? [doc] : doc).some(doc => SelectionManager.Views().some(dv => Doc.AreProtosEqual(dv.rootDoc, doc)))) SelectionManager.DeselectAll(); + if ((doc instanceof Doc ? [doc] : doc).some(doc => SelectionManager.Views().some(dv => Doc.AreProtosEqual(dv.Document, doc)))) SelectionManager.DeselectAll(); if (result.length !== value.length && doc instanceof Doc) { const ind = DocListCast(targetDataDoc[this.props.fieldKey]).indexOf(doc); const prev = ind && DocListCast(targetDataDoc[this.props.fieldKey])[ind - 1]; @@ -316,12 +316,12 @@ export class CollectionTreeView extends CollectionSubView {StrCast(this.rootDoc.layout_explainer)}
; + return !Doc.noviceMode || !this.layoutDoc.layout_explainer ? null :
{StrCast(this.layoutDoc.layout_explainer)}
; } return35 = () => 35; @computed get buttonMenu() { - const menuDoc = Cast(this.rootDoc.layout_headerButton, Doc, null); + const menuDoc = Cast(this.layoutDoc.layout_headerButton, Doc, null); // To create a multibutton menu add a CollectionLinearView return !menuDoc ? null : (
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 426ad2c2f..4f3c5b9a2 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -34,6 +34,7 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionView } from './CollectionView'; import './TabDocView.scss'; import React = require('react'); +import { Docs } from '../../documents/Documents'; const _global = (window /* browser */ || global) /* node */ as any; interface TabDocViewProps { @@ -259,7 +260,7 @@ export class TabDocView extends React.Component { return; } const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps); - const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); + const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Docs.Create.ConfigDocument({}); pinDoc.presentation_targetDoc = anchorDoc ?? doc; pinDoc.title = doc.title + ' - Slide'; pinDoc.data = new List(); // the children of the embedding's layout are the presentation slide children. the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data @@ -271,7 +272,6 @@ export class TabDocView extends React.Component { pinDoc.treeView = ''; // not really needed, but makes key value pane look better pinDoc.treeView_RenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area pinDoc.treeView_HeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. - pinDoc.treeView_ChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. pinDoc.treeView_FieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field pinDoc.treeView_ExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 6e3f8e807..9de74b761 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -19,7 +19,6 @@ import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; import { LinkManager } from '../../util/LinkManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; -import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; @@ -144,7 +143,7 @@ export class TreeView extends React.Component { return NumCast(this.props.treeViewParent.maxEmbedHeight, 200); } @computed get dataDoc() { - return this.props.document.treeView_ChildrenOnRoot ? this.doc : this.doc[DocData]; + return this.doc[DocData]; } @computed get layoutDoc() { return Doc.Layout(this.doc); @@ -333,7 +332,7 @@ export class TreeView extends React.Component { const before = pt[1] < rect.top + rect.height / 2; const inside = pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length); this._header.current!.className = 'treeView-header'; - if (!this.props.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.props.treeView.rootDoc) { + if (!this.props.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.props.treeView.Document) { if (inside) this._header.current!.className += ' treeView-header-inside'; else if (before) this._header.current!.className += ' treeView-header-above'; else if (!before) this._header.current!.className += ' treeView-header-below'; @@ -361,7 +360,7 @@ export class TreeView extends React.Component { _width: 1000, _height: 10, }); - Doc.GetProto(bullet).title = ComputedField.MakeFunction('self.text?.Text'); + Doc.GetProto(bullet).title = ComputedField.MakeFunction('this.text?.Text'); Doc.GetProto(bullet).data = new List([]); DocumentManager.Instance.AddViewRenderedCb(bullet, dv => dv.ComponentView?.setFocus?.()); @@ -838,7 +837,7 @@ export class TreeView extends React.Component { ? [openEmbedding, makeFolder] : this.doc._type_collection === CollectionViewType.Docking ? [] - : this.props.treeView.rootDoc === Doc.MyRecentlyClosed + : this.props.treeView.Document === Doc.MyRecentlyClosed ? [reopenDoc] : [openEmbedding, focusDoc]), ]; @@ -882,8 +881,8 @@ export class TreeView extends React.Component { maxWidth: props?.PanelWidth() || undefined, background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor), outline: SnappingManager.GetIsDragging() ? undefined: `solid ${highlightColor} ${highlightIndex}px`, - paddingLeft: NumCast(treeView.rootDoc.childXPadding, NumCast(treeView.props.childXPadding, Doc.IsComicStyle(doc)?20:0)), - paddingRight: NumCast(treeView.rootDoc.childXPadding, NumCast(treeView.props.childXPadding, Doc.IsComicStyle(doc)?20:0)), + paddingLeft: NumCast(treeView.Document.childXPadding, NumCast(treeView.props.childXPadding, Doc.IsComicStyle(doc)?20:0)), + paddingRight: NumCast(treeView.Document.childXPadding, NumCast(treeView.props.childXPadding, Doc.IsComicStyle(doc)?20:0)), paddingTop: treeView.props.childYPadding, paddingBottom: treeView.props.childYPadding, }}> diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 403fba67b..d6a738084 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -37,6 +37,7 @@ export interface PoolData { zIndex?: number; width?: number; height?: number; + autoDim?: number; // 1 for set to Panel dims, 0 for use width/height as entered backgroundColor?: string; color?: string; opacity?: number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index 856e195a3..38aeea152 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -8,7 +8,7 @@ import React = require('react'); import { CollectionFreeFormView } from './CollectionFreeFormView'; export interface CollectionFreeFormPannableContentsProps { - rootDoc: Doc; + Document: Doc; viewDefDivClick?: ScriptField; children?: React.ReactNode | undefined; transition?: string; @@ -20,7 +20,7 @@ export interface CollectionFreeFormPannableContentsProps { @observer export class CollectionFreeFormPannableContents extends React.Component { @computed get presPaths() { - return CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.pathLines(this.props.rootDoc) : null; + return CollectionFreeFormView.ShowPresPaths ? PresBox.Instance.pathLines(this.props.Document) : null; } // rectangle highlight used when following trail/link to a region of a collection that isn't a document showViewport = (viewport: { panX: number; panY: number; width: number; height: number } | undefined) => diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7f8bde9b4..6babe3c8f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -134,7 +134,7 @@ export class CollectionFreeFormView extends CollectionSubView { CollectionFreeFormDocumentView.animFields.forEach(val => { - const findexed = Cast(doc[`${val.key}-indexed`], listSpec('number'), null); + const findexed = Cast(doc[`${val.key}_indexed`], listSpec('number'), null); findexed?.length <= timecode + 1 && findexed.push(undefined as any as number); }); CollectionFreeFormDocumentView.animStringFields.forEach(val => { - const findexed = Cast(doc[`${val}-indexed`], listSpec('string'), null); + const findexed = Cast(doc[`${val}_indexed`], listSpec('string'), null); findexed?.length <= timecode + 1 && findexed.push(undefined as any as string); }); CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => { - const findexed = Cast(doc[`${val}-indexed`], listSpec(InkField), null); + const findexed = Cast(doc[`${val}_indexed`], listSpec(InkField), null); findexed?.length <= timecode + 1 && findexed.push(undefined as any); }); }); @@ -262,7 +263,7 @@ export class CollectionFreeFormView extends CollectionSubView newBox[field.key]); - CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[`${field.key}-indexed`]); + CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[`${field.key}_indexed`]); CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[field.key]); delete newBox.activeFrame; CollectionFreeFormDocumentView.animFields.forEach((field, i) => field.key !== 'opacity' && (newBox[field.key] = vals[i])); @@ -283,15 +284,15 @@ export class CollectionFreeFormView extends CollectionSubView { - options.docTransform = new Transform(-NumCast(this.rootDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.rootDoc[this.panYFieldKey]) + NumCast(anchor.y), 1); - const res = this.props.focus(this.rootDoc, options); + options.docTransform = new Transform(-NumCast(this.layoutDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.layoutDoc[this.panYFieldKey]) + NumCast(anchor.y), 1); + const res = this.props.focus(this.Document, options); options.docTransform = undefined; return res; }; focus = (anchor: Doc, options: DocFocusOptions) => { if (this._lightboxDoc) return; - if (anchor === this.rootDoc) { + if (anchor === this.Document) { if (options.willZoomCentered && options.zoomScale) { this.fitContentOnce(); options.didMove = true; @@ -300,7 +301,7 @@ export class CollectionFreeFormView extends CollectionSubView, props: Opt, property: string) => { let styleProp = this.props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 - switch (property) { - case StyleProp.BackgroundColor: - const cluster = NumCast(doc?.layout_cluster); - if (this.Document._freeform_useClusters && doc?.type !== DocumentType.IMG) { - if (this._clusterSets.length <= cluster) { - setTimeout(() => doc && this.updateCluster(doc)); - } else { - // choose a cluster color from a palette - const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)']; - styleProp = colors[cluster % colors.length]; - const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor); - // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document - set?.map(s => (styleProp = StrCast(s.backgroundColor))); + if (doc && this.childDocList?.includes(doc)) + switch (property) { + case StyleProp.BackgroundColor: + const cluster = NumCast(doc?.layout_cluster); + if (this.Document._freeform_useClusters && doc?.type !== DocumentType.IMG) { + if (this._clusterSets.length <= cluster) { + setTimeout(() => doc && this.updateCluster(doc)); + } else { + // choose a cluster color from a palette + const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)']; + styleProp = colors[cluster % colors.length]; + const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor); + // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document + set?.map(s => (styleProp = StrCast(s.backgroundColor))); + } } - } - break; - case StyleProp.FillColor: - if (doc && this.Document._currentFrame !== undefined) { - return CollectionFreeFormDocumentView.getStringValues(doc, NumCast(this.Document._currentFrame))?.fillColor; - } - } + break; + case StyleProp.FillColor: + if (doc && this.Document._currentFrame !== undefined) { + return CollectionFreeFormDocumentView.getStringValues(doc, NumCast(this.Document._currentFrame))?.fillColor; + } + } return styleProp; }; @@ -623,7 +625,7 @@ export class CollectionFreeFormView extends CollectionSubView { - this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.rootDoc)); + this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.Document)); this._deleteList = []; this._batch?.end(); }; @@ -752,8 +754,8 @@ export class CollectionFreeFormView extends CollectionSubView { if (!this._deleteList.includes(intersect.inkView)) { this._deleteList.push(intersect.inkView); - SetActiveInkWidth(StrCast(intersect.inkView.rootDoc.stroke_width?.toString()) || '1'); - SetActiveInkColor(StrCast(intersect.inkView.rootDoc.color?.toString()) || 'black'); + 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 (!e.shiftKey) { this._eraserLock++; @@ -785,7 +787,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.Document._isGroup || this.Document[(this.props.viewField ?? '_') + 'freeform_noZoom']) return; + if (this.Document.isGroup || this.Document[(this.props.viewField ?? '_') + 'freeform_noZoom']) return; let deltaScale = deltaY > 0 ? 1 / 1.05 : 1.05; if (deltaScale < 0) deltaScale = -deltaScale; const [x, y] = this.screenToLocalXf.transformPoint(pointX, pointY); @@ -935,15 +937,15 @@ export class CollectionFreeFormView extends CollectionSubView 20) { deltaScale = 20 / invTransform.Scale; } - if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc[this.scaleFieldKey + '_min'])) { + if (deltaScale < 1 && invTransform.Scale <= NumCast(this.Document[this.scaleFieldKey + '_min'])) { this.setPan(0, 0); return; } - if (deltaScale * invTransform.Scale > NumCast(this.rootDoc[this.scaleFieldKey + '_max'], Number.MAX_VALUE)) { - deltaScale = NumCast(this.rootDoc[this.scaleFieldKey + '_max'], 1) / invTransform.Scale; + if (deltaScale * invTransform.Scale > NumCast(this.Document[this.scaleFieldKey + '_max'], Number.MAX_VALUE)) { + deltaScale = NumCast(this.Document[this.scaleFieldKey + '_max'], 1) / invTransform.Scale; } - if (deltaScale * invTransform.Scale < NumCast(this.rootDoc[this.scaleFieldKey + '_min'], this.isAnnotationOverlay ? 1 : 0)) { - deltaScale = NumCast(this.rootDoc[this.scaleFieldKey + '_min'], 1) / invTransform.Scale; + if (deltaScale * invTransform.Scale < NumCast(this.Document[this.scaleFieldKey + '_min'], this.isAnnotationOverlay ? 1 : 0)) { + deltaScale = NumCast(this.Document[this.scaleFieldKey + '_min'], 1) / invTransform.Scale; } const localTransform = invTransform.scaleAbout(deltaScale, x, y); @@ -956,11 +958,11 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom + if (this.Document.isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); if (this.layoutDoc._Transform || this.props.Document.treeView_OutlineMode === TreeViewType.outline) return; e.stopPropagation(); - const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc) + '_nativeHeight'], this.nativeHeight); + const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight); const scrollable = this.isAnnotationOverlay && NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling + 1e-4; switch ( !e.ctrlKey && !e.shiftKey && !e.metaKey && !e.altKey ?// @@ -1024,28 +1026,28 @@ export class CollectionFreeFormView extends CollectionSubView 2 && this.rootDoc.layout_scrollTop === undefined && NumCast(this.rootDoc._freeform_scale, minScale) === minScale) { + } else if (fitYscroll > 2 && this.layoutDoc.layout_scrollTop === undefined && NumCast(this.layoutDoc._freeform_scale, minScale) === minScale) { const maxPanY = minPanY + fitYscroll; const relTop = (panY - minPanY) / (maxPanY - minPanY); - setTimeout(() => (this.rootDoc.layout_scrollTop = relTop * maxScrollTop), 10); + setTimeout(() => (this.layoutDoc.layout_scrollTop = relTop * maxScrollTop), 10); newPanY = minPanY; } !this.Document._verticalScroll && (this.Document[this.panXFieldKey] = this.isAnnotationOverlay ? newPanX : panX); @@ -1055,8 +1057,8 @@ export class CollectionFreeFormView extends CollectionSubView { - const collectionDoc = this.props.docViewPath().lastElement().rootDoc; - if (collectionDoc?._type_collection !== CollectionViewType.Freeform || collectionDoc._freeform_ !== undefined) { + const collectionDoc = this.props.docViewPath().lastElement().Document; + if (collectionDoc?._type_collection !== CollectionViewType.Freeform) { this.setPan( NumCast(this.layoutDoc[this.panXFieldKey]) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(), @@ -1104,7 +1106,7 @@ export class CollectionFreeFormView extends CollectionSubView { const docView = fieldProps.DocumentView?.(); - if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.rootDoc._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { + if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { e.stopPropagation?.(); const below = !e.altKey && e.key !== 'Tab'; const layout_fieldKey = StrCast(docView.LayoutFieldKey); - const newDoc = Doc.MakeCopy(docView.rootDoc, true); - const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)]; + const newDoc = Doc.MakeCopy(docView.Document, true); + const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)]; newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; - if (below) newDoc.y = NumCast(docView.rootDoc.y) + NumCast(docView.rootDoc._height) + 10; - else newDoc.x = NumCast(docView.rootDoc.x) + NumCast(docView.rootDoc._width) + 10; - if (layout_fieldKey !== 'layout' && docView.rootDoc[layout_fieldKey] instanceof Doc) { - newDoc[layout_fieldKey] = docView.rootDoc[layout_fieldKey]; + if (below) newDoc.y = NumCast(docView.Document.y) + NumCast(docView.Document._height) + 10; + else newDoc.x = NumCast(docView.Document.x) + NumCast(docView.Document._width) + 10; + if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) { + newDoc[layout_fieldKey] = docView.Document[layout_fieldKey]; } Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SelectOnLoad = newDoc[Id]; @@ -1228,7 +1230,7 @@ export class CollectionFreeFormView extends CollectionSubView { // create an anchor that saves information about the current state of the freeform view (pan, zoom, view type) - const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.rootDoc }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document._isGroup, type_collection: true, filters: true } }, this.rootDoc); + const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.Document }); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document.isGroup, type_collection: true, filters: true } }, this.Document); if (addAsAnnotation) { if (Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) { @@ -1434,7 +1437,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.Document._isGroup && this.childDocs.length === this.childDocList?.length) { + if (this.Document.isGroup && this.childDocs.length === this.childDocList?.length) { const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: NumCast(cd._width), height: NumCast(cd._height) })); return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); } @@ -1481,7 +1484,7 @@ export class CollectionFreeFormView extends CollectionSubView this.isContentActive(), // if autoreset is on, then whenever the view is selected, it will be restored to it default pan/zoom positions - active => !SnappingManager.GetIsDragging() && this.rootDoc[this.autoResetFieldKey] && active && this.resetView() + active => !SnappingManager.GetIsDragging() && this.dataDoc[this.autoResetFieldKey] && active && this.resetView() ); }) ); @@ -1575,7 +1578,7 @@ export class CollectionFreeFormView extends CollectionSubView disposer?.()); } @@ -1616,9 +1619,9 @@ export class CollectionFreeFormView extends CollectionSubView { - this.rootDoc[this.panXFieldKey] = NumCast(this.rootDoc[this.panXFieldKey + '_reset']); - this.props.Document[this.panYFieldKey] = NumCast(this.rootDoc[this.panYFieldKey + '_reset']); - this.rootDoc[this.scaleFieldKey] = NumCast(this.rootDoc[this.scaleFieldKey + '_reset'], 1); + this.layoutDoc[this.panXFieldKey] = NumCast(this.dataDoc[this.panXFieldKey + '_reset']); + this.layoutDoc[this.panYFieldKey] = NumCast(this.dataDoc[this.panYFieldKey + '_reset']); + this.layoutDoc[this.scaleFieldKey] = NumCast(this.dataDoc[this.scaleFieldKey + '_reset'], 1); }; /// /// resetView restores a freeform collection to unit scale and centered at (0,0) UNLESS @@ -1626,11 +1629,11 @@ export class CollectionFreeFormView extends CollectionSubView { - this.rootDoc[this.autoResetFieldKey] = !this.rootDoc[this.autoResetFieldKey]; - if (this.rootDoc[this.autoResetFieldKey]) { - this.rootDoc[this.panXFieldKey + '_reset'] = this.rootDoc[this.panXFieldKey]; - this.rootDoc[this.panYFieldKey + '_reset'] = this.rootDoc[this.panYFieldKey]; - this.rootDoc[this.scaleFieldKey + '_reset'] = this.rootDoc[this.scaleFieldKey]; + this.dataDoc[this.autoResetFieldKey] = !this.dataDoc[this.autoResetFieldKey]; + if (this.dataDoc[this.autoResetFieldKey]) { + this.dataDoc[this.panXFieldKey + '_reset'] = this.dataDoc[this.panXFieldKey]; + this.dataDoc[this.panYFieldKey + '_reset'] = this.dataDoc[this.panYFieldKey]; + this.dataDoc[this.scaleFieldKey + '_reset'] = this.dataDoc[this.scaleFieldKey]; } }; @@ -1639,8 +1642,8 @@ export class CollectionFreeFormView extends CollectionSubView (Doc.UserDoc().defaultTextLayout = undefined), icon: 'eye' }); - appearanceItems.push({ description: `Pin View`, event: () => this.props.pinToPres(this.rootDoc, { pinViewport: MarqueeView.CurViewBounds(this.rootDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' }); + appearanceItems.push({ description: `Pin View`, event: () => this.props.pinToPres(this.Document, { pinViewport: MarqueeView.CurViewBounds(this.dataDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' }); !Doc.noviceMode && appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: 'compress-arrows-alt' }); this.props.renderDepth && appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' }); - this.props.Document._isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' }); + this.props.Document.isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' }); !Doc.noviceMode ? appearanceItems.push({ description: 'Arrange contents in grid', event: this.layoutDocsInGrid, icon: 'table' }) : null; !Doc.noviceMode ? appearanceItems.push({ description: (this.Document._freeform_useClusters ? 'Hide' : 'Show') + ' Clusters', event: () => this.updateClusters(!this.Document._freeform_useClusters), icon: 'braille' }) : null; @@ -1681,7 +1684,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.Document._isGroup && this.props.Document.transcription) { + if (this.props.Document.isGroup && this.props.Document.transcription) { const text = StrCast(this.props.Document.transcription); const lines = text.split('\n'); const height = 30 + 15 * lines.length; @@ -1697,9 +1700,9 @@ export class CollectionFreeFormView extends CollectionSubView()) => { - if (visited.has(this.rootDoc)) return; - visited.add(this.rootDoc); - showGroupDragTarget && (this.GroupChildDrag = BoolCast(this.Document._isGroup)); + if (visited.has(this.Document)) return; + visited.add(this.Document); + showGroupDragTarget && (this.GroupChildDrag = BoolCast(this.Document.isGroup)); const activeDocs = this.getActiveDocuments(); const size = this.screenToLocalXf.transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] }; @@ -1708,14 +1711,14 @@ export class CollectionFreeFormView extends CollectionSubView doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to activeDocs - .filter(doc => doc._isGroup && SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc)) + .filter(doc => doc.isGroup && SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc)) .forEach(doc => DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.dragStarting?.(snapToDraggedDoc, false, visited)); const horizLines: number[] = []; const vertLines: number[] = []; const invXf = this.screenToLocalXf.inverse(); snappableDocs - .filter(doc => !doc._isGroup && (snapToDraggedDoc || (SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc)))) + .filter(doc => !doc.isGroup && (snapToDraggedDoc || (SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc)))) .forEach(doc => { const { left, top, width, height } = docDims(doc); const topLeftInScreen = invXf.transformPoint(left, top); @@ -1783,7 +1786,7 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? undefined : this.nudge} addDocTab={this.addDocTab} slowLoadDocuments={this.slowLoadDocuments} @@ -1828,7 +1831,7 @@ export class CollectionFreeFormView extends CollectionSubView this.nativeDimScaling; @@ -1849,7 +1852,7 @@ export class CollectionFreeFormView extends CollectionSubView Math.max(0, this.props.PanelHeight() - 30); lightboxScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-15, -15); onPassiveWheel = (e: WheelEvent) => { - const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc) + '_nativeHeight'], this.nativeHeight); + const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight); const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling; this.props.isSelected() && !scrollable && e.preventDefault(); }; @@ -1930,14 +1933,14 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY dv && DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => { if (!focused) { - const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; + const selfFfview = !dv.Document.isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; let containers = dv.props.docViewPath(); let parFfview = dv.CollectionFreeFormView; for (var cont of containers) { parFfview = parFfview ?? cont.CollectionFreeFormView; } - while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView; - const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview + while (parFfview?.Document.isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView; + const ffview = selfFfview && selfFfview.layoutDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview ffview?.zoomSmoothlyAboutPt(ffview.screenToLocalXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); Doc.linkFollowHighlight(dv?.props.Document, false); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 2092ecb7a..18b9b4423 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -348,6 +348,7 @@ export class MarqueeView extends React.Component { Doc.GetProto(doc).data = new List(selected); + Doc.GetProto(doc).isGroup = makeGroup; Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform'; doc._freeform_panX = doc._freeform_panY = 0; return doc; @@ -355,7 +356,6 @@ export class MarqueeView extends React.Component this.props.isSelected() || this.props.isContentActive(); - isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : undefined); + isChildContentActive = () => (this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive)) ? true : undefined); /** * * @param layout @@ -187,6 +187,7 @@ export class CollectionGridView extends CollectionSubView() { return ( ); } diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index 4267a9059..a06ed3a2d 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -48,7 +48,7 @@ export class CollectionLinearView extends CollectionSubView() { componentDidMount() { this._widthDisposer = reaction( - () => 5 + NumCast(this.rootDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsOpen ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (NumCast(doc._width) || this.dimension()) + tot + 4, 0) : 0), + () => 5 + NumCast(this.dataDoc.linearBtnWidth, this.dimension()) + (this.layoutDoc.linearView_IsOpen ? this.childDocs.filter(doc => !doc.hidden).reduce((tot, doc) => (NumCast(doc._width) || this.dimension()) + tot + 4, 0) : 0), width => this.childDocs.length && (this.layoutDoc._width = width), { fireImmediately: true } ); @@ -58,7 +58,7 @@ export class CollectionLinearView extends CollectionSubView() { if (ele) this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); }; - dimension = () => NumCast(this.rootDoc._height); + dimension = () => NumCast(this.layoutDoc._height); getTransform = (ele: Opt) => { if (!ele) return Transform.Identity(); const { scale, translateX, translateY } = Utils.GetScreenTransform(ele); @@ -183,7 +183,7 @@ export class CollectionLinearView extends CollectionSubView() { PanelWidth={doc[Width]} PanelHeight={nested || doc._height ? doc[Height] : this.dimension} renderDepth={this.props.renderDepth + 1} - dontRegisterView={BoolCast(this.rootDoc.childDontRegisterViews)} + dontRegisterView={BoolCast(this.Document.childDontRegisterViews)} focus={emptyFunction} styleProvider={this.props.styleProvider} docViewPath={returnEmptyDoclist} @@ -215,7 +215,7 @@ export class CollectionLinearView extends CollectionSubView() { toggleStatus={BoolCast(this.layoutDoc.linearView_IsOpen)} onClick={() => { this.layoutDoc.linearView_IsOpen = !isExpanded; - ScriptCast(this.rootDoc.onClick)?.script.run({ this: this.rootDoc }, console.log); + ScriptCast(this.Document.onClick)?.script.run({ this: this.Document }, console.log); }} tooltip={isExpanded ? 'Close' : 'Open'} fillWidth={true} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss index cb0d5e03f..4e2968933 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss @@ -17,7 +17,7 @@ } .contentFittingDocumentView { - width: unset; + margin: auto; } .label-wrapper { diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index c2586fb4b..05ec0448b 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -219,8 +219,8 @@ export class CollectionMulticolumnView extends CollectionSubView() { if (this.childDocs.includes(d)) { if (dropInd > this.childDocs.indexOf(d)) dropInd--; } - Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d); - Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); + Doc.RemoveDocFromList(this.dataDoc, this.props.fieldKey, d); + Doc.AddDocToList(this.dataDoc, this.props.fieldKey, d, DocListCast(this.dataDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); } }) ); @@ -235,18 +235,25 @@ export class CollectionMulticolumnView extends CollectionSubView() { isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); isChildContentActive = () => { - const childDocsActive = this.props.childDocumentsActive?.() ?? this.rootDoc.childDocumentsActive; + const childDocsActive = this.props.childDocumentsActive?.() ?? this.Document.childDocumentsActive; return this.props.isContentActive?.() === false || childDocsActive === false ? false // : this.props.isDocumentActive?.() && childDocsActive ? true : undefined; }; - getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number, shouldNotScale: () => boolean) => { + getDisplayDoc = (childLayout: Doc) => { + const width = () => this.lookupPixels(childLayout); + const height = () => this.props.PanelHeight() - 2 * NumCast(this.layoutDoc._yMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0); + const dxf = () => + this.lookupIndividualTransform(childLayout) + .translate(-NumCast(this.layoutDoc._xMargin), -NumCast(this.layoutDoc._yMargin)) + .scale(this.props.NativeDimScaling?.() || 1); + const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(childLayout.freeform_fitContentsToBox); return ( ); }; @@ -288,26 +296,15 @@ export class CollectionMulticolumnView extends CollectionSubView() { @computed private get contents(): JSX.Element[] | null { const { childLayoutPairs } = this; - const { Document, PanelHeight } = this.props; const collector: JSX.Element[] = []; for (let i = 0; i < childLayoutPairs.length; i++) { const { layout } = childLayoutPairs[i]; - const aspect = Doc.NativeAspect(layout, undefined, true); - const width = () => this.lookupPixels(layout); - const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); - const docwidth = () => (layout._layout_reflowHorizontal ? width() : Math.min(height() * aspect, width())); - const docheight = () => Math.min(docwidth() / aspect, height()); - const dxf = () => - this.lookupIndividualTransform(layout) - .translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin)) - .scale(this.props.NativeDimScaling?.() || 1); - const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(layout.freeform_fitContentsToBox); collector.push( -
- {this.getDisplayDoc(layout, dxf, docwidth, docheight, shouldNotScale)} +
+ {this.getDisplayDoc(layout)}
, this.childDocs.indexOf(d)) dropInd--; } - Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d); - Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); + Doc.RemoveDocFromList(this.dataDoc, this.props.fieldKey, d); + Doc.AddDocToList(this.dataDoc, this.props.fieldKey, d, DocListCast(this.dataDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1); } }) ); @@ -231,14 +231,21 @@ export class CollectionMultirowView extends CollectionSubView() { isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); isChildContentActive = () => { - const childDocsActive = this.props.childDocumentsActive?.() ?? this.rootDoc.childDocumentsActive; + const childDocsActive = this.props.childDocumentsActive?.() ?? this.Document.childDocumentsActive; return this.props.isContentActive?.() === false || childDocsActive === false ? false // : this.props.isDocumentActive?.() && childDocsActive ? true : undefined; }; - getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number, shouldNotScale: () => boolean) => { + getDisplayDoc = (layout: Doc) => { + const height = () => this.lookupPixels(layout); + const width = () => this.props.PanelWidth() - 2 * NumCast(this.layoutDoc._xMargin) - (BoolCast(this.layoutDoc.showWidthLabels) ? 20 : 0); + const dxf = () => + this.lookupIndividualTransform(layout) + .translate(-NumCast(this.layoutDoc._xMargin), -NumCast(this.layoutDoc._yMargin)) + .scale(this.props.NativeDimScaling?.() || 1); + const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(layout.freeform_fitContentsToBox); return ( ); }; @@ -284,24 +292,13 @@ export class CollectionMultirowView extends CollectionSubView() { @computed private get contents(): JSX.Element[] | null { const { childLayoutPairs } = this; - const { Document, PanelWidth } = this.props; const collector: JSX.Element[] = []; for (let i = 0; i < childLayoutPairs.length; i++) { const { layout } = childLayoutPairs[i]; - const aspect = Doc.NativeAspect(layout, undefined, true); - const height = () => this.lookupPixels(layout); - const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); - const docheight = () => Math.min(width() / aspect, height()); - const docwidth = () => (layout._layout_reflowHorizontal ? width() : Math.min(width(), docheight() * aspect)); - const dxf = () => - this.lookupIndividualTransform(layout) - .translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin) - (height() - docheight()) / 2) - .scale(this.props.NativeDimScaling?.() || 1); - const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(layout.freeform_fitContentsToBox); collector.push( -
- {this.getDisplayDoc(layout, dxf, docwidth, docheight, shouldNotScale)} - +
+ {this.getDisplayDoc(layout)} +
, Doc.AreProtosEqual(DocCast(doc.embedContainer), this.rootDoc)); + const selected = SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.Document)); if (!selected.length) { for (const sel of SelectionManager.Docs()) { const contextPath = DocumentManager.GetContextPath(sel, true); - if (contextPath.includes(this.rootDoc)) { - const parentInd = contextPath.indexOf(this.rootDoc); + if (contextPath.includes(this.Document)) { + const parentInd = contextPath.indexOf(this.Document); return parentInd < contextPath.length - 1 ? [contextPath[parentInd + 1]] : []; } } @@ -146,7 +146,7 @@ export class CollectionSchemaView extends CollectionSubView() { Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1])); this._keysDisposer = observe( - this.rootDoc[this.fieldKey ?? 'data'] as List, + this.dataDoc[this.fieldKey ?? 'data'] as List, change => { switch (change.type as any) { case 'splice': @@ -154,7 +154,7 @@ export class CollectionSchemaView extends CollectionSubView() { (change as any).added.forEach((doc: Doc) => // for each document added Doc.GetAllPrototypes(doc.value as Doc).forEach(proto => // for all of its prototypes (and itself) Object.keys(proto).forEach(action(key => // check if any of its keys are new, and add them - !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo('')))))); + !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo(key, key === 'author')))))); break; case 'update': //let oldValue = change.oldValue; // fill this in if the entire child list will ever be reassigned with a new list } diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 9d5b533d1..2c251d3cf 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -102,7 +102,7 @@ export class SchemaTableCell extends React.Component { } @computed get defaultCellContent() { - const { color, textDecoration, fieldProps } = SchemaTableCell.renderProps(this.props); + const { color, textDecoration, fieldProps, pointerEvents } = SchemaTableCell.renderProps(this.props); return (
{ color, textDecoration, width: '100%', + pointerEvents, }}> - [ where, { checkResult: () =>(editorView ? (where === 'vcent' ? SelectionManager.Docs().some(doc => doc.layout_centered): + [ where, { checkResult: () =>(editorView ? (where === 'vcent' ? RichTextMenu.Instance.textVcenter: (RichTextMenu.Instance.textAlign === where)): - where === 'vcent' ? BoolCast(Doc.UserDoc().layout_centered): + where === 'vcent' ? BoolCast(Doc.UserDoc()._layout_centered): (Doc.UserDoc().textAlign ===where) ? true:false), - toggle: () => (editorView?.state ? (where === 'vcent' ? SelectionManager.Docs().forEach(doc => doc.layout_centered = !doc.layout_centered): + toggle: () => (editorView?.state ? (where === 'vcent' ? RichTextMenu.Instance.vcenterToggle(editorView, editorView.dispatch): RichTextMenu.Instance.align(editorView, editorView.dispatch, where)): - where === 'vcent' ? Doc.UserDoc().layout_centered = !Doc.UserDoc().layout_centered: + where === 'vcent' ? Doc.UserDoc()._layout_centered = !Doc.UserDoc()._layout_centered: (Doc.UserDoc().textAlign = where))}]); // prettier-ignore // prettier-ignore const listings:attrfuncs[] = (['bullet','decimal'] as attrname[]).map(list => diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 8d80f1364..807a77233 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -366,8 +366,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.Transition; // prettier-ignore w_DataTransition = () => this.DataTransition; // prettier-ignore - PanelWidth = () => this.Width > 0 ? this.Width : this.props.PanelWidth?.(); // prettier-ignore - PanelHeight = () => this.Height > 0 ? this.Height : this.props.PanelHeight?.(); // prettier-ignore + PanelWidth = () => this.props.autoDim ? this.props.PanelWidth?.() : this.Width; // prettier-ignore + PanelHeight = () => this.props.autoDim ? this.props.PanelHeight?.() : this.Height; // prettier-ignore @action componentDidUpdate() { this.WrapperKeys.forEach(keys => ((this as any)[keys.upper] = (this.props as any)[keys.lower])); @@ -113,7 +115,7 @@ export interface CollectionFreeFormDocumentViewProps { @observer export class CollectionFreeFormDocumentView extends DocComponent() { get displayName() { // this makes mobx trace() statements more descriptive - return 'CollectionFreeFormDocumentView(' + this.rootDoc.title + ')'; + return 'CollectionFreeFormDocumentView(' + this.Document.title + ')'; } // prettier-ignore public static animFields: { key: string; val?: number }[] = [ { key: 'x' }, @@ -148,14 +150,14 @@ export class CollectionFreeFormDocumentView extends DocComponent { - p[val.key] = Cast(doc[`${val.key}-indexed`], listSpec('number'), fillIn ? [NumCast(doc[val.key], val.val)] : []).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as number); + p[val.key] = Cast(doc[`${val.key}_indexed`], listSpec('number'), fillIn ? [NumCast(doc[val.key], val.val)] : []).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as number); return p; }, {} as { [val: string]: Opt }); } public static getStringValues(doc: Doc, time: number) { return CollectionFreeFormDocumentView.animStringFields.reduce((p, val) => { - p[val] = Cast(doc[`${val}-indexed`], listSpec('string'), [StrCast(doc[val])]).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as string); + p[val] = Cast(doc[`${val}_indexed`], listSpec('string'), [StrCast(doc[val])]).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as string); return p; }, {} as { [val: string]: Opt }); } @@ -163,40 +165,52 @@ export class CollectionFreeFormDocumentView extends DocComponent }) { const timecode = Math.round(time); Object.keys(vals).forEach(val => { - const findexed = Cast(d[`${val}-indexed`], listSpec('string'), []).slice(); + const findexed = Cast(d[`${val}_indexed`], listSpec('string'), []).slice(); findexed[timecode] = vals[val] as any as string; - d[`${val}-indexed`] = new List(findexed); + d[`${val}_indexed`] = new List(findexed); }); } public static setValues(time: number, d: Doc, vals: { [val: string]: Opt }) { const timecode = Math.round(time); Object.keys(vals).forEach(val => { - const findexed = Cast(d[`${val}-indexed`], listSpec('number'), []).slice(); + const findexed = Cast(d[`${val}_indexed`], listSpec('number'), []).slice(); findexed[timecode] = vals[val] as any as number; - d[`${val}-indexed`] = new List(findexed); + d[`${val}_indexed`] = new List(findexed); }); } + public static gotoKeyFrame(doc: Doc, newFrame: number) { + if (doc) { + const childDocs = DocListCast(doc[Doc.LayoutFieldKey(doc)]); + const currentFrame = Cast(doc._currentFrame, 'number', null); + if (currentFrame === undefined) { + doc._currentFrame = 0; + CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0); + } + CollectionFreeFormView.updateKeyframe(undefined, [...childDocs, doc], currentFrame || 0); + doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame); + } + } public static setupKeyframes(docs: Doc[], currTimecode: number, makeAppear: boolean = false) { docs.forEach(doc => { if (doc.appearFrame === undefined) doc.appearFrame = currTimecode; - if (!doc['opacity-indexed']) { + if (!doc['opacity_indexed']) { // opacity is unlike other fields because it's value should not be undefined before it appears to enable it to fade-in - doc['opacity-indexed'] = new List(numberRange(currTimecode + 1).map(t => (!doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1))); + doc['opacity_indexed'] = new List(numberRange(currTimecode + 1).map(t => (!doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1))); } CollectionFreeFormDocumentView.animFields.forEach(val => (doc[val.key] = ComputedField.MakeInterpolatedNumber(val.key, 'activeFrame', doc, currTimecode, val.val))); CollectionFreeFormDocumentView.animStringFields.forEach(val => (doc[val] = ComputedField.MakeInterpolatedString(val, 'activeFrame', doc, currTimecode))); CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => (doc[val] = ComputedField.MakeInterpolatedDataField(val, 'activeFrame', doc, currTimecode))); const targetDoc = doc; // data fields, like rtf 'text' exist on the data doc, so //doc !== targetDoc && (targetDoc.embedContainer = doc.embedContainer); // the computed fields don't see the layout doc -- need to copy the embedContainer to the data doc (HACK!!!) and set the activeFrame on the data doc (HACK!!!) - targetDoc.activeFrame = ComputedField.MakeFunction('self.embedContainer?._currentFrame||0'); + targetDoc.activeFrame = ComputedField.MakeFunction('this.embedContainer?._currentFrame||0'); targetDoc.dataTransition = 'inherit'; }); } @action public float = () => { - const topDoc = this.rootDoc; + const topDoc = this.Document; const containerDocView = this.props.docViewPath().lastElement(); const screenXf = containerDocView?.screenToLocalTransform(); if (screenXf) { @@ -238,7 +252,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { if (this.CollectionFreeFormView.isAnyChildContentActive()) return undefined; - const isGroup = this.rootDoc._isGroup && (!this.rootDoc.backgroundColor || this.rootDoc.backgroundColor === 'transparent'); + const isGroup = this.Document.isGroup && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent'); return isGroup ? (this.props.isDocumentActive?.() ? 'group' : this.props.isGroupActive?.() ? 'child' : 'inactive') : this.props.isGroupActive?.() ? 'child' : undefined; }; public static CollectionFreeFormDocViewClassName = 'collectionFreeFormDocumentView-container'; @@ -265,3 +279,6 @@ export class CollectionFreeFormDocumentView extends DocComponent { click = (e: React.MouseEvent) => { const clickScript = (this.props as any).onClick as Opt; - clickScript?.script.run({ this: this.props.Document, self: this.props.RootDoc, scale: this.props.scaling }); + clickScript?.script.run({ this: this.props.Document, self: this.props.Document, scale: this.props.scaling }); }; onInput = (e: React.FormEvent) => { const onInputScript = (this.props as any).onInput as Opt; - onInputScript?.script.run({ this: this.props.Document, self: this.props.RootDoc, value: (e.target as any).textContent }); + onInputScript?.script.run({ this: this.props.Document, self: this.props.Document, value: (e.target as any).textContent }); }; render() { const style: { [key: string]: any } = {}; - const divKeys = OmitKeys(this.props, ['children', 'dragStarting', 'dragEnding', 'htmltag', 'RootDoc', 'scaling', 'Document', 'key', 'onInput', 'onClick', '__proto__']).omit; + const divKeys = OmitKeys(this.props, ['children', 'dragStarting', 'dragEnding', 'htmltag', 'scaling', 'Document', 'key', 'onInput', 'onClick', '__proto__']).omit; const replacer = (match: any, expr: string, offset: any, string: any) => { - // bcz: this executes a script to convert a propery expression string: { script } into a value - return (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ self: this.props.RootDoc, this: this.props.Document, scale: this.props.scaling }).result as string) || ''; + // bcz: this executes a script to convert a property expression string: { script } into a value + return (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ self: this.props.Document, this: this.props.Document, scale: this.props.scaling }).result as string) || ''; }; Object.keys(divKeys).map((prop: string) => { const p = (this.props as any)[prop] as string; @@ -119,9 +118,6 @@ export class HTMLtag extends React.Component { @observer export class DocumentContentsView extends React.Component< DocumentViewProps & { - isSelected: () => boolean; - select: (ctrl: boolean) => void; - NativeDimScaling?: () => number; setHeight?: (height: number) => void; layout_fieldKey: string; } @@ -137,6 +133,10 @@ export class DocumentContentsView extends React.Component< return '

Loading layout

'; } + componentDidUpdate(prevProps: Readonly void) | undefined; layout_fieldKey: string }>, prevState: Readonly<{}>, snapshot?: any): void { + Object.keys(prevProps).forEach(pkey => (prevProps as any)[pkey] !== (this.props as any)[pkey] && console.log(pkey + ' ' + (prevProps as any)[pkey] + ' ' + (this.props as any)[pkey])); + } + get dataDoc() { const proto = this.props.DataDoc || Doc.GetProto(this.props.Document); return proto instanceof Promise ? undefined : proto; @@ -170,7 +170,6 @@ export class DocumentContentsView extends React.Component< ]; const list = { ...OmitKeys(this.props, [...docOnlyProps], '').omit, - RootDoc: Cast(this.layoutDoc?.rootDocument, Doc, null) || this.layoutDoc, Document: this.layoutDoc, DataDoc: this.dataDoc, onClick: onClick, @@ -195,7 +194,7 @@ export class DocumentContentsView extends React.Component< // replace HTML with corresponding HTML tag as in: becomes const replacer2 = (match: any, p1: string, offset: any, string: any) => { - return `; + return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.ShowTitle) as Opt; } @computed get NativeDimScaling() { return this.props.NativeDimScaling?.() || 1; @@ -302,13 +302,13 @@ export class DocumentViewInternal extends DocComponent dv.docView?._mainCont.current); - const selected = views.length > 1 && views.some(dv => dv.rootDoc === this.Document) ? views : [this.props.DocumentView()]; - const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.rootDoc)); + const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this.props.DocumentView()]; + const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document)); const [left, top] = this.props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0); dragData.offset = this.props .ScreenToLocalTransform() @@ -417,7 +417,7 @@ export class DocumentViewInternal extends DocComponent dv.docView!._mainCont.current!), dragData, @@ -430,8 +430,8 @@ export class DocumentViewInternal extends DocComponent { const targetMatch = - Doc.AreProtosEqual(anchor, this.rootDoc) || // anchor is this document, so anchor's properties apply to this document - (DocCast(anchor)?.layout_unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.rootDoc)) // the anchor is an layout_unrendered annotation on this document, so anchor properties apply to this document + Doc.AreProtosEqual(anchor, this.Document) || // anchor is this document, so anchor's properties apply to this document + (DocCast(anchor)?.layout_unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.Document)) // the anchor is an layout_unrendered annotation on this document, so anchor properties apply to this document ? true : false; return targetMatch && PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined; @@ -450,23 +450,22 @@ export class DocumentViewInternal extends DocComponent= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) { let stopPropagate = true; let preventDefault = true; - !this.rootDoc._keepZWhenDragged && this.props.bringToFront(this.rootDoc); + !this.layoutDoc._keepZWhenDragged && this.props.bringToFront(this.Document); if (this._doubleTap) { const defaultDblclick = this.props.defaultDoubleClick?.() || this.Document.defaultDoubleClick; if (this.onDoubleClickHandler?.script) { const { clientX, clientY, shiftKey, altKey, ctrlKey } = e; // or we could call e.persist() to capture variables // prettier-ignore const func = () => this.onDoubleClickHandler.script.run( { - this: this.layoutDoc, - self: this.rootDoc, + this: this.Document, scriptContext: this.props.scriptContext, documentView: this.props.DocumentView(), clientX, clientY, altKey, shiftKey, ctrlKey, value: undefined, }, console.log ); UndoManager.RunInBatch(() => (func().result?.select === true ? this.props.select(false) : ''), 'on double click'); - } else if (!Doc.IsSystem(this.rootDoc) && (defaultDblclick === undefined || defaultDblclick === 'default')) { - UndoManager.RunInBatch(() => LightboxView.Instance.AddDocTab(this.rootDoc, OpenWhere.lightbox), 'double tap'); + } else if (!Doc.IsSystem(this.Document) && (defaultDblclick === undefined || defaultDblclick === 'default')) { + UndoManager.RunInBatch(() => LightboxView.Instance.AddDocTab(this.Document, OpenWhere.lightbox), 'double tap'); SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } else { @@ -488,8 +487,7 @@ export class DocumentViewInternal extends DocComponent UndoManager.RunInBatch(func, 'click ' + this.rootDoc.title); + clickFunc = () => UndoManager.RunInBatch(func, 'click ' + this.Document.title); } else { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) { @@ -516,7 +514,7 @@ export class DocumentViewInternal extends DocComponent (sendToBack ? this.props.DocumentView().props.bringToFront(this.rootDoc, true) : + clickFunc ?? (() => (sendToBack ? this.props.DocumentView().props.bringToFront(this.Document, true) : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this.props.select(e.ctrlKey||e.shiftKey, e.metaKey))); const waitFordblclick = this.props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; @@ -538,7 +536,7 @@ export class DocumentViewInternal extends DocComponent { if (DocumentView.LongPress) { - if (this.rootDoc.undoIgnoreFields) { + if (this.Document.undoIgnoreFields) { runInAction(() => (UndoStack.HideInline = !UndoStack.HideInline)); } else { this.props.select(false); @@ -563,10 +561,10 @@ export class DocumentViewInternal extends DocComponent { - const hadOnClick = this.rootDoc.onClick; + const hadOnClick = this.Document.onClick; this.noOnClick(); this.Document.onClick = hadOnClick ? undefined : FollowLinkScript(); this.Document.waitForDoubleClickToClick = hadOnClick ? undefined : 'never'; @@ -653,11 +651,11 @@ export class DocumentViewInternal extends DocComponent { - if (e && this.rootDoc._layout_hideContextMenu && Doc.noviceMode) { + if (e && this.layoutDoc._layout_hideContextMenu && Doc.noviceMode) { e.preventDefault(); e.stopPropagation(); //!this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false); @@ -738,7 +736,7 @@ export class DocumentViewInternal extends DocComponent { - if (this.rootDoc.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this.props.isSelected() && SelectionManager.SelectView(this.props.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. + if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this.props.isSelected() && SelectionManager.SelectView(this.props.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY)); }; if (navigator.userAgent.includes('Macintosh')) { @@ -751,11 +749,9 @@ export class DocumentViewInternal extends DocComponent - cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: 'sticky-note' }) + cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.Document, scriptContext: this.props.scriptContext }), icon: 'sticky-note' }) ); - this.props - .contextMenuItems?.() - .forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: item.icon as IconProp })); + this.props.contextMenuItems?.().forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.Document, scriptContext: this.props.scriptContext }), icon: item.icon as IconProp })); if (!this.props.Document.isFolder) { const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layout_fieldKey)], Doc, null); @@ -765,22 +761,22 @@ export class DocumentViewInternal extends DocComponent LightboxView.Instance.SetLightboxDoc(this.rootDoc), icon: 'external-link-alt' }); } - this.rootDoc.type === DocumentType.PRES && appearanceItems.push({ description: 'Pin', event: () => this.props.pinToPres(this.rootDoc, {}), icon: 'eye' }); + this.Document.type === DocumentType.PRES && appearanceItems.push({ description: 'Pin', event: () => this.props.pinToPres(this.rootDoc, {}), icon: 'eye' }); !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !appearance && appearanceItems.length && cm.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'compass' }); - if (!Doc.IsSystem(this.rootDoc) && this.rootDoc.type !== DocumentType.PRES && ![CollectionViewType.Docking, CollectionViewType.Tree].includes(this.rootDoc._type_collection as any)) { + if (!Doc.IsSystem(this.Document) && this.Document.type !== DocumentType.PRES && ![CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._type_collection as any)) { const existingOnClick = cm.findByDescription('OnClick...'); const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; if (this.props.bringToFront !== emptyFunction) { const zorders = cm.findByDescription('ZOrder...'); const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : []; - zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: 'arrow-up' }); - zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: 'arrow-down' }); + zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.Document, false)), icon: 'arrow-up' }); + zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.Document, true)), icon: 'arrow-down' }); zorderItems.push({ - description: !this.rootDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged', - event: undoBatch(action(() => (this.rootDoc._keepZWhenDragged = !this.rootDoc._keepZWhenDragged))), + description: !this.layoutDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged', + event: undoBatch(action(() => (this.layoutDoc._keepZWhenDragged = !this.layoutDoc._keepZWhenDragged))), icon: 'hand-point-up', }); !zorders && cm.addItem({ description: 'Z Order...', addDivider: true, noexpand: true, subitems: zorderItems, icon: 'layer-group' }); @@ -816,7 +812,7 @@ export class DocumentViewInternal extends DocComponent Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: 'concierge-bell' }); moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => (this.Document._chromeHidden = !this.Document._chromeHidden), icon: 'project-diagram' }); @@ -833,9 +829,9 @@ export class DocumentViewInternal extends DocComponent Doc.Zip(this.props.Document) }); - (this.rootDoc._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' }); + (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.props.DocumentView()), icon: 'users' }); if (this.props.removeDocument && Doc.ActiveDashboard !== this.props.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions) constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); @@ -847,8 +843,8 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'keyboard' }); - !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.props.Document), icon: 'hand-point-right' }); - !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.props.Document[DocData]), icon: 'hand-point-right' }); + !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.Document), icon: 'hand-point-right' }); + !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.dataDoc), icon: 'hand-point-right' }); let documentationDescription: string | undefined = undefined; let documentationLink: string | undefined = undefined; @@ -902,7 +898,7 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; panelHeight = () => this.props.PanelHeight() - this.headerMargin; @@ -931,7 +927,7 @@ export class DocumentViewInternal extends DocComponent - (link.link_matchEmbeddings ? link.link_anchor_1 === this.rootDoc : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.rootDoc)) || - (link.link_matchEmbeddings ? link.link_anchor_2 === this.rootDoc : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.rootDoc)) || - ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.rootDoc)) || - ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.rootDoc)) + (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) || + (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) || + ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) || + ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document)) ); } @computed get allLinks() { TraceMobx(); - return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); + return LinkManager.Instance.getAllRelatedLinks(this.Document); } hideLink = computedFn((link: Doc) => () => (link.link_displayLine = false)); @computed get allLinkEndpoints() { @@ -1020,7 +1015,7 @@ export class DocumentViewInternal extends DocComponent
)); @@ -1143,7 +1138,7 @@ export class DocumentViewInternal extends DocComponent @@ -1191,8 +1186,8 @@ export class DocumentViewInternal extends DocComponent { - if (this.rootDoc.layout_showTitle) { - this.rootDoc._layout_showTitle = field; + if (this.layoutDoc.layout_showTitle) { + this.layoutDoc._layout_showTitle = field; } else if (!this.props.layout_showTitle) { Doc.UserDoc().layout_showTitle = field; } @@ -1216,11 +1211,11 @@ export class DocumentViewInternal extends DocComponent (showTitle.split(';').length !== 1 ? '#' + showTitle : Field.toKeyValueString(this.rootDoc, showTitle.split(';')[0]))} + GetValue={() => (showTitle.split(';').length !== 1 ? '#' + showTitle : Field.toKeyValueString(this.Document, showTitle.split(';')[0]))} SetValue={undoBatch((input: string) => { if (input?.startsWith('#')) { - if (this.rootDoc.layout_showTitle) { - this.rootDoc._layout_showTitle = input?.substring(1); + if (this.layoutDoc.layout_showTitle) { + this.layoutDoc._layout_showTitle = input?.substring(1); } else if (!this.props.layout_showTitle) { Doc.UserDoc().layout_showTitle = input?.substring(1) ?? 'author_date'; } @@ -1246,7 +1241,7 @@ export class DocumentViewInternal extends DocComponent { TraceMobx(); - return !DocCast(this.Document) || GetEffectiveAcl(this.Document[DocData]) === AclPrivate + return !DocCast(this.Document) || GetEffectiveAcl(this.dataDoc) === AclPrivate ? null : this.docContents ?? (
<> - {this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.rootDoc[Animation], this.rootDoc)} + {this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} {borderPath?.jsx}
@@ -1377,7 +1372,7 @@ export class DocumentView extends React.Component { private _disposers: { [name: string]: IReactionDisposer } = {}; public clearViewTransition = () => { this.ViewTimer && clearTimeout(this.ViewTimer); - this.rootDoc._viewTransition = undefined; + this.layoutDoc._viewTransition = undefined; }; public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource); @@ -1385,15 +1380,15 @@ export class DocumentView extends React.Component { public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => { this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer); - this.rootDoc[Animation] = presEffect; - this.AnimEffectTimer = setTimeout(() => (this.rootDoc[Animation] = undefined), timeInMs); + this.Document[Animation] = presEffect; + this.AnimEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs); }; public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => { - this.rootDoc._viewTransition = `${transProp} ${timeInMs}ms`; + this.layoutDoc._viewTransition = `${transProp} ${timeInMs}ms`; if (dataTrans) this.rootDoc._dataTransition = `${transProp} ${timeInMs}ms`; this.ViewTimer && clearTimeout(this.ViewTimer); return (this.ViewTimer = setTimeout(() => { - this.rootDoc._viewTransition = undefined; + this.layoutDoc._viewTransition = undefined; this.rootDoc._dataTransition = 'inherit'; afterTrans?.(); }, timeInMs + 10)); @@ -1421,7 +1416,7 @@ export class DocumentView extends React.Component { DocServer.GetRefField(docId).then(docx => LightboxView.Instance.SetLightboxDoc( (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection - Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(self, self.target)') }, docId) + Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) ) ); } @@ -1445,16 +1440,16 @@ export class DocumentView extends React.Component { return this.docView?._componentView; } get allLinks() { - return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.rootDoc || link.link_anchor_2 === this.rootDoc); + return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.rootDoc); } get LayoutFieldKey() { return this.docView?.LayoutFieldKey || 'layout'; } @computed get layout_fitWidth() { - return this.docView?._componentView?.layout_fitWidth?.() ?? this.props.layout_fitWidth?.(this.rootDoc) ?? this.layoutDoc?.layout_fitWidth; + return this.docView?._componentView?.layout_fitWidth?.() ?? this.props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth; } @computed get anchorViewDoc() { - return this.props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.rootDoc['link_anchor_2']) : this.props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.rootDoc['link_anchor_1']) : undefined; + return this.props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this.props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; } @computed get hideLinkButton() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkBtn + (this.isSelected() ? ':selected' : '')); @@ -1526,7 +1521,7 @@ export class DocumentView extends React.Component { return this.props.CollectionFreeFormDocumentView?.(); } - public toggleNativeDimensions = () => this.docView && this.rootDoc.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); + public toggleNativeDimensions = () => this.docView && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); public getBounds = () => { if (!this.docView?.ContentDiv || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { return undefined; @@ -1560,7 +1555,7 @@ export class DocumentView extends React.Component { const deiconifyLayout = Cast(this.Document.deiconifyLayout, 'string', null); this.switchViews(deiconifyLayout ? true : false, deiconifyLayout, finalFinished); this.Document.deiconifyLayout = undefined; - this.props.bringToFront(this.rootDoc); + this.props.bringToFront(this.Document); } } @undoBatch @@ -1574,8 +1569,8 @@ export class DocumentView extends React.Component { this.docView && (this.docView._animateScalingTo = 0.1); // shrink doc setTimeout( action(() => { - if (useExistingLayout && custom && this.rootDoc['layout_' + view]) { - this.rootDoc.layout_fieldKey = 'layout_' + view; + if (useExistingLayout && custom && this.Document['layout_' + view]) { + this.Document.layout_fieldKey = 'layout_' + view; } else { this.setCustomView(custom, view); } @@ -1592,6 +1587,7 @@ export class DocumentView extends React.Component { ); }; + layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth); scaleToScreenSpace = () => (1 / (this.props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale; docViewPathFunc = () => this.docViewPath; isSelected = () => this.SELECTED; @@ -1600,7 +1596,7 @@ export class DocumentView extends React.Component { else { SelectionManager.SelectView(this, extendSelection); if (focusSelection) { - DocumentManager.Instance.showDocument(this.rootDoc, { + DocumentManager.Instance.showDocument(this.Document, { willZoomCentered: true, zoomScale: 0.9, zoomTime: 500, @@ -1608,6 +1604,7 @@ export class DocumentView extends React.Component { } } }; + ShouldNotScale = () => this.shouldNotScale; NativeWidth = () => this.effectiveNativeWidth; NativeHeight = () => this.effectiveNativeHeight; PanelWidth = () => this.panelWidth; @@ -1622,8 +1619,8 @@ export class DocumentView extends React.Component { @action componentDidMount() { - this.rootDoc[DocViews].add(this); - this._disposers.updateContentsScript = reaction(() => ScriptCast(this.rootDoc.updateContentsScript)?.script?.run({ this: this.rootDoc, self: this.rootDoc }).result, emptyFunction); + this.Document[DocViews].add(this); + this._disposers.updateContentsScript = reaction(() => ScriptCast(this.Document.updateContentsScript)?.script?.run({ this: this.Document }).result, emptyFunction); this._disposers.height = reaction( // increase max auto height if document has been resized to be greater than current max () => NumCast(this.layoutDoc._height), @@ -1636,7 +1633,7 @@ export class DocumentView extends React.Component { } @action componentWillUnmount() { - this.rootDoc[DocViews].delete(this); + this.Document[DocViews].delete(this); Object.values(this._disposers).forEach(disposer => disposer?.()); !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); } @@ -1662,7 +1659,7 @@ export class DocumentView extends React.Component { console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} />
, { ...(this.htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc, - this.rootDoc + this.Document )}
@@ -1683,15 +1680,14 @@ export class DocumentView extends React.Component { style={{ transition: 'inherit', // this.props.dataTransition, transform: `translate(${this.centeringX}px, ${this.centeringY}px)`, - width: xshift ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`, - height: this.props.forceAutoHeight - ? undefined - : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`), + width: xshift ?? `${this.props.PanelWidth() - this.Xshift * 2}px`, + height: this.props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this.props.PanelWidth()}px`), }}> { NativeDimScaling={this.NativeDimScaling} isSelected={this.isSelected} select={this.select} + layout_fitWidth={this.layout_fitWidthFunc} ScreenToLocalTransform={this.screenToLocalTransform} focus={this.props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} @@ -1719,7 +1716,7 @@ ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) { }); ScriptingGlobals.add(function deiconifyViewToLightbox(documentView: DocumentView) { - LightboxView.Instance.AddDocTab(documentView.rootDoc, OpenWhere.lightbox, 'layout'); //, 0); + LightboxView.Instance.AddDocTab(documentView.Document, OpenWhere.lightbox, 'layout'); //, 0); }); ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) { diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index de5ad1631..ba5370360 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -26,7 +26,6 @@ export enum ButtonType { TextButton = 'textBtn', MenuButton = 'menuBtn', DropdownList = 'dropdownList', - DropdownButton = 'dropdownBtn', ClickButton = 'clickBtn', ToggleButton = 'toggleBtn', ColorButton = 'colorBtn', @@ -78,7 +77,7 @@ export class FontIconBox extends DocComponent() { // Determining UI Specs @computed get label() { - return StrCast(this.rootDoc.icon_label, StrCast(this.rootDoc.title)); + return StrCast(this.dataDoc.icon_label, StrCast(this.Document.title)); } Icon = (color: string, iconFalse?: boolean) => { let icon; @@ -91,13 +90,13 @@ export class FontIconBox extends DocComponent() { return !icon ? null : icon === 'pres-trail' ? TrailsIcon(color) : ; }; @computed get dropdown() { - return BoolCast(this.rootDoc.dropDownOpen); + return BoolCast(this.Document.dropDownOpen); } @computed get buttonList() { - return StrListCast(this.rootDoc.btnList); + return StrListCast(this.Document.btnList); } @computed get type() { - return StrCast(this.rootDoc.btnType); + return StrCast(this.Document.btnType); } /** @@ -131,8 +130,8 @@ export class FontIconBox extends DocComponent() { type = 'slider'; break; } - const numScript = (value?: number) => ScriptCast(this.rootDoc.script).script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: value === undefined }); - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); + const numScript = (value?: number) => ScriptCast(this.Document.script).script.run({ this: this.Document, value, _readOnly_: value === undefined }); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); // Script for checking the outcome of the toggle const checkResult = Number(Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3))); @@ -144,52 +143,21 @@ export class FontIconBox extends DocComponent() { showPlusMinus={false} tooltip={this.label} type={Type.PRIM} - min={NumCast(this.rootDoc.numBtnMin, 0)} - max={NumCast(this.rootDoc.numBtnMax, 100)} + min={NumCast(this.dataDoc.numBtnMin, 0)} + max={NumCast(this.dataDoc.numBtnMax, 100)} number={checkResult} - setNumber={undoable(value => numScript(value), `${this.rootDoc.title} button set from list`)} + setNumber={undoable(value => numScript(value), `${this.Document.title} button set from list`)} fillWidth /> ); } - /** - * Dropdown button - */ - @computed get dropdownButton() { - const active: string = StrCast(this.rootDoc.dropDownOpen); - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); - return ( -
{ - this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen; - this.noTooltip = this.rootDoc.dropDownOpen; - Doc.UnBrushAllDocs(); - })}> - {this.Icon(color)} - {!this.label || !FontIconBox.ShowIconLabels ? null : ( -
- {' '} - {this.label}{' '} -
- )} -
- -
- {this.rootDoc.dropDownOpen ?
{/* DROPDOWN BOX CONTENTS */}
: null} -
- ); - } - dropdownItemDown = (e: React.PointerEvent, value: string | number) => { setupMoveUpEvents( this, e, (e: PointerEvent) => { - return ScriptCast(this.rootDoc.onDragScript)?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: { doc: value, e } }).result; + return ScriptCast(this.Document.onDragScript)?.script.run({ this: this.Document, value: { doc: value, e } }).result; }, emptyFunction, emptyFunction @@ -201,7 +169,7 @@ export class FontIconBox extends DocComponent() { * Dropdown list */ @computed get dropdownListButton() { - const script = ScriptCast(this.rootDoc.script); + const script = ScriptCast(this.Document.script); let noviceList: string[] = []; let text: string | undefined; @@ -237,7 +205,7 @@ export class FontIconBox extends DocComponent() { } noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Carousel3D, CollectionViewType.Stacking, CollectionViewType.NoteTaking]; } else { - text = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result; + text = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result; // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily); getStyle = (val: string) => ({ fontFamily: val }); } @@ -255,7 +223,7 @@ export class FontIconBox extends DocComponent() { return ( script.script.run({ this: this.layoutDoc, self: this.rootDoc, value }), `dropdown select ${this.label}`)} + setSelectedVal={undoable(value => script.script.run({ this: this.Document, value }), `dropdown select ${this.label}`)} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} type={Type.TERT} @@ -270,7 +238,7 @@ export class FontIconBox extends DocComponent() { } @computed get colorScript() { - return ScriptCast(this.rootDoc.script); + return ScriptCast(this.Document.script); } colorBatch: UndoManager.Batch | undefined; @@ -278,18 +246,18 @@ export class FontIconBox extends DocComponent() { * Color button */ @computed get colorButton() { - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const curColor = this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result ?? 'transparent'; - const tooltip: string = StrCast(this.rootDoc.toolTip); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const curColor = this.colorScript?.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result ?? 'transparent'; + const tooltip: string = StrCast(this.Document.toolTip); return ( { if (!this.colorBatch) this.colorBatch = UndoManager.StartBatch(`Set ${tooltip} color`); - this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }); + this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false }); }} setFinalColor={value => { - this.colorScript?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: value, _readOnly_: false }); + this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false }); this.colorBatch?.end(); this.colorBatch = undefined; }} @@ -306,13 +274,13 @@ export class FontIconBox extends DocComponent() { } @computed get multiToggleButton() { // Determine the type of toggle button - const tooltip: string = StrCast(this.rootDoc.toolTip); + const tooltip: string = StrCast(this.Document.toolTip); - const script = ScriptCast(this.rootDoc.onClick); - const toggleStatus = script ? script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result : false; + const script = ScriptCast(this.Document.onClick); + const toggleStatus = script ? script.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result : false; // Colors - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const items = DocListCast(this.rootDoc.data); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const items = DocListCast(this.dataDoc.data); return ( () { color={color} background={SettingsManager.userBackgroundColor} label={this.label} - items={DocListCast(this.rootDoc.data).map(item => ({ + items={DocListCast(this.dataDoc.data).map(item => ({ icon: , tooltip: StrCast(item.toolTip), val: StrCast(item.toolType), @@ -336,14 +304,14 @@ export class FontIconBox extends DocComponent() { @computed get toggleButton() { // Determine the type of toggle button - const buttonText: string = StrCast(this.rootDoc.buttonText); - const tooltip: string = StrCast(this.rootDoc.toolTip); + const buttonText = StrCast(this.dataDoc.buttonText); + const tooltip = StrCast(this.Document.toolTip); - const script = ScriptCast(this.rootDoc.onClick); - const toggleStatus = script ? script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result : false; + const script = ScriptCast(this.Document.onClick); + const toggleStatus = script ? script.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result : false; // Colors - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor); return ( () { //background={SettingsManager.userBackgroundColor} icon={this.Icon(color)!} label={this.label} - onPointerDown={() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: !toggleStatus, _readOnly_: false })} + onPointerDown={() => script.script.run({ this: this.Document, value: !toggleStatus, _readOnly_: false })} /> ); } @@ -365,20 +333,20 @@ export class FontIconBox extends DocComponent() { * Default */ @computed get defaultButton() { - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); - const tooltip: string = StrCast(this.rootDoc.toolTip); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor); + const tooltip: string = StrCast(this.Document.toolTip); return ; } @computed get editableText() { // Script for running the toggle - const script = ScriptCast(this.rootDoc.script); + const script = ScriptCast(this.Document.script); // Function to run the script - const checkResult = script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result; + const checkResult = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result; - const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value, _readOnly_: false }).result; + const setValue = (value: string, shiftDown?: boolean): boolean => script?.script.run({ this: this.Document, value, _readOnly_: false }).result; return {}} />; @@ -386,16 +354,16 @@ export class FontIconBox extends DocComponent() {
- script?.script.run({ this: this.layoutDoc, self: this.rootDoc, value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} /> + script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result} SetValue={setValue} oneLine={true} contents={checkResult} />
); } render() { - const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color); - const tooltip = StrCast(this.rootDoc.toolTip); - const scriptFunc = () => ScriptCast(this.rootDoc.onClick)?.script.run({ this: this.layoutDoc, self: this.rootDoc, _readOnly_: false }); + const color = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color); + const tooltip = StrCast(this.Document.toolTip); + const scriptFunc = () => ScriptCast(this.Document.onClick)?.script.run({ this: this.Document, self: this.Document, _readOnly_: false }); const btnProps = { tooltip, icon: this.Icon(color)!, label: this.label }; // prettier-ignore switch (this.type) { @@ -405,15 +373,14 @@ export class FontIconBox extends DocComponent() { case ButtonType.EditableText: return this.editableText; case ButtonType.DropdownList: return this.dropdownListButton; case ButtonType.ColorButton: return this.colorButton; - case ButtonType.DropdownButton: return this.dropdownButton; case ButtonType.MultiToggleButton: return this.multiToggleButton; case ButtonType.ToggleButton: return this.toggleButton; case ButtonType.ClickButton: case ButtonType.ToolButton: return ; case ButtonType.TextButton: return - + */}
)}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 8b3531da8..2ac9c7bfb 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { Toggle, ToggleType, Type } from 'browndash-components'; diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index ad5431c8e..545734e5b 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { CursorProperty } from 'csstype'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index 9e5f09479..9be01df18 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, trace } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index ad8144466..c5677e2ba 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -12,7 +12,7 @@ import { computePassLayout, computeStarburstLayout } from './collectionFreeForm' import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import './CollectionPileView.scss'; import { CollectionSubView } from './CollectionSubView'; -import React = require('react'); +import * as React from 'react'; @observer export class CollectionPileView extends CollectionSubView() { diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 7fee1cda6..92b5470ae 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 59e0c60b9..e5f71a2f8 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CursorProperty } from 'csstype'; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 9bd412fb8..3282eb4b4 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index f082ca0da..40b2f9644 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -24,7 +24,7 @@ import { ViewBoxBaseComponent } from '../DocComponent'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { LoadingBox } from '../nodes/LoadingBox'; import { CollectionView, CollectionViewProps } from './CollectionView'; -import React = require('react'); +import * as React from 'react'; export interface SubCollectionViewProps extends CollectionViewProps { isAnyChildContentActive: () => boolean; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 8d114761a..e65f24702 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -21,7 +21,7 @@ import { computePivotLayout, computeTimelineLayout, ViewDefBounds } from './coll import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTimeView.scss'; -import React = require('react'); +import * as React from 'react'; @observer export class CollectionTimeView extends CollectionSubView() { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 1315decb2..5c165fe70 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -26,7 +26,7 @@ import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTreeView.scss'; import { TreeView } from './TreeView'; -import React = require('react'); +import * as React from 'react'; const _global = (window /* browser */ || global) /* node */ as any; export type collectionTreeViewProps = { diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index def4beca3..4a1d702b8 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -33,7 +33,7 @@ import { CollectionDockingView } from './CollectionDockingView'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionView } from './CollectionView'; import './TabDocView.scss'; -import React = require('react'); +import * as React from 'react'; import { Docs } from '../../documents/Documents'; import { ComputedField } from '../../../fields/ScriptField'; const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 0de1068f7..b5666b917 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -35,7 +35,7 @@ import { CollectionTreeView, TreeViewType } from './CollectionTreeView'; import { CollectionView } from './CollectionView'; import { TreeSort } from './TreeSort'; import './TreeView.scss'; -import React = require('react'); +import * as React from 'react'; export interface TreeViewProps { treeView: CollectionTreeView; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx index 00505dbe3..99ee5ef4e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx @@ -2,7 +2,7 @@ import { observer } from 'mobx-react'; import { Doc } from '../../../../fields/Doc'; import { NumCast } from '../../../../fields/Types'; import './CollectionFreeFormView.scss'; -import React = require('react'); +import * as React from 'react'; export interface CollectionFreeFormViewBackgroundGridProps { panX: () => number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index d6a738084..b8c0967c1 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -5,7 +5,7 @@ import { RefField } from '../../../../fields/RefField'; import { listSpec } from '../../../../fields/Schema'; import { Cast, NumCast, StrCast } from '../../../../fields/Types'; import { aggregateBounds } from '../../../../Utils'; -import React = require('react'); +import * as React from 'react'; export interface ViewDefBounds { type: string; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 0c0d45a30..fac5e849b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -13,7 +13,7 @@ import { SnappingManager } from '../../../util/SnappingManager'; import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../../nodes/DocumentView'; import './CollectionFreeFormLinkView.scss'; -import React = require('react'); +import * as React from 'react'; export interface CollectionFreeFormLinkViewProps { A: DocumentView; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 420e6a318..779a0bf96 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -5,7 +5,7 @@ import { DocumentManager } from '../../../util/DocumentManager'; import { LightboxView } from '../../LightboxView'; import './CollectionFreeFormLinksView.scss'; import { CollectionFreeFormLinkView } from './CollectionFreeFormLinkView'; -import React = require('react'); +import * as React from 'react'; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index 38aeea152..f54726a00 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -4,7 +4,7 @@ import { Doc } from '../../../../fields/Doc'; import { ScriptField } from '../../../../fields/ScriptField'; import { PresBox } from '../../nodes/trails/PresBox'; import './CollectionFreeFormView.scss'; -import React = require('react'); +import * as React from 'react'; import { CollectionFreeFormView } from './CollectionFreeFormView'; export interface CollectionFreeFormPannableContentsProps { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 9e8d92d7d..1118c6a72 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -9,7 +9,7 @@ import { listSpec } from '../../../../fields/Schema'; import { Cast } from '../../../../fields/Types'; import { CollectionViewProps } from '../CollectionView'; import './CollectionFreeFormView.scss'; -import React = require('react'); +import * as React from 'react'; import v5 = require('uuid/v5'); @observer diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d242b1356..fbad01cad 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -50,7 +50,7 @@ import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannable import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; -import React = require('react'); +import * as React from 'react'; export type collectionFreeformViewProps = { NativeWidth?: () => number; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index 607f9fb95..d231197fb 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 18b9b4423..330c13e97 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -24,7 +24,7 @@ import { PreviewCursor } from '../../PreviewCursor'; import { SubCollectionViewProps } from '../CollectionSubView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; -import React = require('react'); +import * as React from 'react'; import { freeformScrollMode } from '../../../util/SettingsManager'; interface MarqueeViewProps { diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.scss b/src/client/views/collections/collectionLinear/CollectionLinearView.scss index d0c14a21d..3c2f5ccd7 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.scss +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.scss @@ -18,9 +18,9 @@ user-select: none; } - > input:not(:checked) ~ &.true { - background-color: transparent; - } + // > input:not(:checked) ~ &.true { + // background-color: transparent; + // } .collectionLinearView { display: flex; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 030f9953c..029d39f88 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, ObservableMap, observe } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index 65e47f441..0e37198bb 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 03697b40a..53f4a4d51 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { IconButton, Size } from 'browndash-components'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index 3082c632d..3d9cf1893 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -6,7 +6,7 @@ import { DocumentView } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenu.scss'; import { LinkMenuGroup } from './LinkMenuGroup'; -import React = require('react'); +import * as React from 'react'; import { SettingsManager } from '../../util/SettingsManager'; interface Props { diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index 5453ed07b..91142b90b 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -7,7 +7,7 @@ import { LinkManager } from '../../util/LinkManager'; import { DocumentView } from '../nodes/DocumentView'; import './LinkMenu.scss'; import { LinkMenuItem } from './LinkMenuItem'; -import React = require('react'); +import * as React from 'react'; import { DocumentType } from '../../documents/DocumentTypes'; interface LinkMenuGroupProps { diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 611771fff..042acff05 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -17,7 +17,7 @@ import { undoBatch } from '../../util/UndoManager'; import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; -import React = require('react'); +import * as React from 'react'; interface LinkMenuItemProps { groupType: string; diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index a36c8d778..5460a6daf 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -10,7 +10,7 @@ import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { SearchBox } from '../search/SearchBox'; import { DefaultStyleProvider } from '../StyleProvider'; import './LinkPopup.scss'; -import React = require('react'); +import * as React from 'react'; interface LinkPopupProps { linkFrom?: () => Doc | undefined; diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx index 9662b2fea..3e7f5be74 100644 --- a/src/client/views/linking/LinkRelationshipSearch.tsx +++ b/src/client/views/linking/LinkRelationshipSearch.tsx @@ -1,6 +1,6 @@ import { observer } from 'mobx-react'; import './LinkEditor.scss'; -import React = require('react'); +import * as React from 'react'; interface link_relationshipSearchProps { results: string[] | undefined; diff --git a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx index a085e4a66..23027808f 100644 --- a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx +++ b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx @@ -25,11 +25,13 @@ export const Recommendation = (props: IRecommendation) => { switch (type) { case 'YouTube': console.log('create ', type, 'document'); - doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315, transcript }); + doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315 }); + doc.transcript = transcript ? JSON.stringify(transcript) : undefined; break; case 'Video': console.log('create ', type, 'document'); - doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315, transcript }); + doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315 }); + doc.transcript = transcript ? JSON.stringify(transcript) : undefined; break; case 'Webpage': console.log('create ', type, 'document'); diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index dacdbe986..8b9c5ae67 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, runInAction } from 'mobx'; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 6195a155d..624f28413 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -14,7 +14,7 @@ import { DocComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './CollectionFreeFormDocumentView.scss'; import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; -import React = require('react'); +import * as React from 'react'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentViewProps { diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index 2a20d935b..852d39800 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { action } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 9fd4fbcaa..72a473114 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -13,7 +13,7 @@ import './ComparisonBox.scss'; import { DocumentView, DocumentViewProps } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; -import React = require('react'); +import * as React from 'react'; @observer export class ComparisonBox extends ViewBoxAnnotatableComponent() { diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 4dbd67485..f9e7a4617 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -277,6 +277,7 @@ export class PieChart extends React.Component { return 'slice'; } ) + // @ts-ignore .attr('d', arc) .on('click', onPointClick) .on('mouseover', onHover) diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 4b58bfe48..b0c94a06a 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -46,7 +46,7 @@ import { ScriptingBox } from './ScriptingBox'; import { PresBox } from './trails/PresBox'; import { VideoBox } from './VideoBox'; import { WebBox } from './WebBox'; -import React = require('react'); +import * as React from 'react'; import XRegExp = require('xregexp'); const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index ce3650749..9d233ead5 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -15,7 +15,7 @@ import { DocumentView } from './DocumentView'; import { LinkDescriptionPopup } from './LinkDescriptionPopup'; import { TaskCompletionBox } from './TaskCompletedBox'; import { PinProps } from './trails'; -import React = require('react'); +import * as React from 'react'; import _ = require('lodash'); interface DocumentLinksButtonProps { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index bfbe3389f..f6a14eab1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -51,7 +51,7 @@ import { KeyValueBox } from './KeyValueBox'; import { LinkAnchorBox } from './LinkAnchorBox'; import { PresEffect, PresEffectDirection } from './trails'; import { PinProps, PresBox } from './trails/PresBox'; -import React = require('react'); +import * as React from 'react'; const { Howl } = require('howler'); interface Window { diff --git a/src/client/views/nodes/FaceRectangle.tsx b/src/client/views/nodes/FaceRectangle.tsx index 20afa4565..8d03bf57a 100644 --- a/src/client/views/nodes/FaceRectangle.tsx +++ b/src/client/views/nodes/FaceRectangle.tsx @@ -1,14 +1,14 @@ -import React = require("react"); -import { observer } from "mobx-react"; -import { observable, runInAction } from "mobx"; -import { RectangleTemplate } from "./FaceRectangles"; +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { observable, runInAction } from 'mobx'; +import { RectangleTemplate } from './FaceRectangles'; @observer export default class FaceRectangle extends React.Component<{ rectangle: RectangleTemplate }> { @observable private opacity = 0; componentDidMount() { - setTimeout(() => runInAction(() => this.opacity = 1), 500); + setTimeout(() => runInAction(() => (this.opacity = 1)), 500); } render() { @@ -18,12 +18,11 @@ export default class FaceRectangle extends React.Component<{ rectangle: Rectangl style={{ ...rectangle.style, opacity: this.opacity, - transition: "1s ease opacity", - position: "absolute", - borderRadius: 5 + transition: '1s ease opacity', + position: 'absolute', + borderRadius: 5, }} /> ); } - -} \ No newline at end of file +} diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx index 0d1e063af..26e720c0d 100644 --- a/src/client/views/nodes/FaceRectangles.tsx +++ b/src/client/views/nodes/FaceRectangles.tsx @@ -1,9 +1,9 @@ -import React = require("react"); -import { Doc, DocListCast } from "../../../fields/Doc"; -import { Cast, NumCast } from "../../../fields/Types"; -import { observer } from "mobx-react"; -import { Id } from "../../../fields/FieldSymbols"; -import FaceRectangle from "./FaceRectangle"; +import * as React from 'react'; +import { Doc, DocListCast } from '../../../fields/Doc'; +import { Cast, NumCast } from '../../../fields/Types'; +import { observer } from 'mobx-react'; +import { Id } from '../../../fields/FieldSymbols'; +import FaceRectangle from './FaceRectangle'; interface FaceRectanglesProps { document: Doc; @@ -18,7 +18,6 @@ export interface RectangleTemplate { @observer export class FaceRectangles extends React.Component { - render() { const faces = DocListCast(this.props.document.faces); const templates: RectangleTemplate[] = faces.map(faceDoc => { @@ -33,14 +32,15 @@ export class FaceRectangles extends React.Component { } as React.CSSProperties; return { id: rectangle[Id], - style: style + style: style, }; }); return (
- {templates.map(rectangle => )} + {templates.map(rectangle => ( + + ))}
); } - -} \ No newline at end of file +} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 219e3025a..f4c5167a5 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; import { DateField } from '../../../fields/DateField'; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index d28d71fe3..336891a18 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -35,7 +35,7 @@ import { FaceRectangles } from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import './ImageBox.scss'; import { PinProps, PresBox } from './trails'; -import React = require('react'); +import * as React from 'react'; export const pageSchema = createSchema({ googlePhotosUrl: 'string', diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 0c6377c3a..d2325a807 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -20,7 +20,7 @@ import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { ImageBox } from './ImageBox'; import './KeyValueBox.scss'; import { KeyValuePair } from './KeyValuePair'; -import React = require('react'); +import * as React from 'react'; export type KVPScript = { script: CompiledScript; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 577685636..8f3c75f54 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -12,7 +12,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; import './KeyValueBox.scss'; import './KeyValuePair.scss'; -import React = require('react'); +import * as React from 'react'; import { DocCast } from '../../../fields/Types'; import { Tooltip } from '@material-ui/core'; import { DocumentOptions, FInfo } from '../../documents/Documents'; diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index cf157c3a9..d10cbac5e 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -12,7 +12,7 @@ import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkDocPreview } from './LinkDocPreview'; -import React = require('react'); +import * as React from 'react'; import globalCssVariables = require('../global/globalCssVariables.scss'); @observer diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 743075c89..ed448ecfb 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { Bezier } from 'bezier-js'; import { computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index c45045a8a..32300d60a 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../../fields/Doc'; diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index ad5324b3e..b5fb6db86 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -18,7 +18,7 @@ import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; -import React = require('react'); +import * as React from 'react'; interface LinkDocPreviewProps { linkDoc?: Doc; diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx index f6680aac0..e6c1db0af 100644 --- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IReactionDisposer, ObservableMap, reaction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/nodes/MapBox/MapPushpinBox.tsx b/src/client/views/nodes/MapBox/MapPushpinBox.tsx index 56f0a49b8..590f8735c 100644 --- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx +++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx @@ -2,7 +2,7 @@ import { observer } from 'mobx-react'; // import { SettingsManager } from '../../../util/SettingsManager'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from '../FieldView'; -import React = require('react'); +import * as React from 'react'; import { computed } from 'mobx'; import { MapBox } from './MapBox'; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 9787de0ab..8de8498d7 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -31,7 +31,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { ImageBox } from './ImageBox'; import './PDFBox.scss'; import { PinProps, PresBox } from './trails'; -import React = require('react'); +import * as React from 'react'; @observer export class PDFBox extends ViewBoxAnnotatableComponent() { diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index cd1ff17dd..c498a58d6 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -15,11 +15,11 @@ import { ViewBoxAnnotatableComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from './../FieldView'; import './PhysicsSimulationBox.scss'; import InputField from './PhysicsSimulationInputField'; -import * as questions from './PhysicsSimulationQuestions.json'; -import * as tutorials from './PhysicsSimulationTutorial.json'; +import questions from './PhysicsSimulationQuestions.json'; +import tutorials from './PhysicsSimulationTutorial.json'; import Wall from './PhysicsSimulationWall'; import Weight from './PhysicsSimulationWeight'; -import React = require('react'); +import * as React from 'react'; interface IWallProps { length: number; diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx index d595a499e..c704863f5 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx @@ -1,6 +1,6 @@ import { TextField, InputAdornment } from '@mui/material'; import { Doc } from '../../../../fields/Doc'; -import React = require('react'); +import * as React from 'react'; import TaskAltIcon from '@mui/icons-material/TaskAlt'; import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; import { isNumber } from 'lodash'; diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx index 8cc1d0fbf..696352296 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx @@ -1,34 +1,33 @@ -import React = require('react'); +import * as React from 'react'; export interface Force { - magnitude: number; - directionInDegrees: number; + magnitude: number; + directionInDegrees: number; } export interface IWallProps { - length: number; - xPos: number; - yPos: number; - angleInDegrees: number; + length: number; + xPos: number; + yPos: number; + angleInDegrees: number; } export default class Wall extends React.Component { + constructor(props: any) { + super(props); + } - constructor(props: any) { - super(props) - } + wallStyle = { + width: this.props.angleInDegrees == 0 ? this.props.length + '%' : '5px', + height: this.props.angleInDegrees == 0 ? '5px' : this.props.length + '%', + position: 'absolute' as 'absolute', + left: this.props.xPos + '%', + top: this.props.yPos + '%', + backgroundColor: '#6c7b8b', + margin: 0, + padding: 0, + }; - wallStyle = { - width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "5px", - height: this.props.angleInDegrees == 0 ? "5px" : this.props.length + "%", - position: "absolute" as "absolute", - left: this.props.xPos + "%", - top: this.props.yPos + "%", - backgroundColor: "#6c7b8b", - margin: 0, - padding: 0, - }; - - render () { - return (
); - } -}; + render() { + return
; + } +} diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx index 2165c8ba9..99333991f 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx @@ -1,7 +1,7 @@ import { computed, IReactionDisposer, reaction } from 'mobx'; import { observer } from 'mobx-react'; import './PhysicsSimulationBox.scss'; -import React = require('react'); +import * as React from 'react'; interface IWallProps { length: number; diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index 7f0956e51..191877cb5 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -1,8 +1,8 @@ -import React = require("react"); -import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import "./RadialMenu.scss"; -import { RadialMenuItem, RadialMenuProps } from "./RadialMenuItem"; +import * as React from 'react'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import './RadialMenu.scss'; +import { RadialMenuItem, RadialMenuProps } from './RadialMenuItem'; @observer export class RadialMenu extends React.Component { @@ -23,11 +23,10 @@ export class RadialMenu extends React.Component { public used: boolean = false; - catchTouch = (te: React.TouchEvent) => { te.stopPropagation(); te.preventDefault(); - } + }; @action onPointerDown = (e: PointerEvent) => { @@ -35,8 +34,8 @@ export class RadialMenu extends React.Component { this._mouseX = e.clientX; this._mouseY = e.clientY; this.used = false; - document.addEventListener("pointermove", this.onPointerMove); - } + document.addEventListener('pointermove', this.onPointerMove); + }; @observable private _closest: number = -1; @@ -60,11 +59,10 @@ export class RadialMenu extends React.Component { } } this._closest = closest; - } - else { + } else { this._closest = -1; } - } + }; @action onPointerUp = (e: PointerEvent) => { this.used = true; @@ -75,43 +73,41 @@ export class RadialMenu extends React.Component { this._shouldDisplay = false; } this._shouldDisplay && (this._display = true); - document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener('pointermove', this.onPointerMove); if (this._closest !== -1 && this._items?.length > this._closest) { this._items[this._closest].event(); } - } + }; componentWillUnmount() { - document.removeEventListener("pointerdown", this.onPointerDown); + document.removeEventListener('pointerdown', this.onPointerDown); - document.removeEventListener("pointerup", this.onPointerUp); + document.removeEventListener('pointerup', this.onPointerUp); this._reactionDisposer && this._reactionDisposer(); } @action componentDidMount = () => { - document.addEventListener("pointerdown", this.onPointerDown); - document.addEventListener("pointerup", this.onPointerUp); + document.addEventListener('pointerdown', this.onPointerDown); + document.addEventListener('pointerup', this.onPointerUp); this.previewcircle(); this._reactionDisposer = reaction( () => this._shouldDisplay, - () => this._shouldDisplay && !this._mouseDown && runInAction(() => this._display = true) + () => this._shouldDisplay && !this._mouseDown && runInAction(() => (this._display = true)) ); - } + }; componentDidUpdate = () => { this.previewcircle(); - } + }; @observable private _pageX: number = 0; @observable private _pageY: number = 0; @observable _display: boolean = false; @observable private _yRelativeToTop: boolean = true; - @observable private _width: number = 0; @observable private _height: number = 0; - getItems() { return this._items; } @@ -133,7 +129,7 @@ export class RadialMenu extends React.Component { this._mouseX = x; this._mouseY = y; this._shouldDisplay = true; - } + }; // @computed // get pageX() { // const x = this._pageX; @@ -168,7 +164,7 @@ export class RadialMenu extends React.Component { this.clearItems(); this._display = false; this._shouldDisplay = false; - } + }; @action openMenu = (x: number, y: number) => { @@ -176,56 +172,52 @@ export class RadialMenu extends React.Component { this._pageY = y; this._shouldDisplay; this._display = true; - } + }; @action clearItems() { this._items = []; } - previewcircle() { - if (document.getElementById("newCanvas") !== null) { - const c: any = document.getElementById("newCanvas"); + if (document.getElementById('newCanvas') !== null) { + const c: any = document.getElementById('newCanvas'); if (c.getContext) { - const ctx = c.getContext("2d"); + const ctx = c.getContext('2d'); ctx.beginPath(); ctx.arc(150, 150, 50, 0, 2 * Math.PI); - ctx.fillStyle = "white"; + ctx.fillStyle = 'white'; ctx.fill(); - ctx.font = "12px Arial"; - ctx.fillStyle = "black"; - ctx.textAlign = "center"; - let description = ""; + ctx.font = '12px Arial'; + ctx.fillStyle = 'black'; + ctx.textAlign = 'center'; + let description = ''; if (this._closest !== -1) { description = this._items[this._closest].description; } if (description.length > 15) { description = description.slice(0, 12); - description += "..."; + description += '...'; } ctx.fillText(description, 150, 150, 90); } } } - render() { if (!this._display) { return null; } - const style = this._yRelativeToTop ? { left: this._pageX - 130, top: this._pageY - 130 } : - { left: this._pageX - 130, top: this._pageY - 130 }; + const style = this._yRelativeToTop ? { left: this._pageX - 130, top: this._pageY - 130 } : { left: this._pageX - 130, top: this._pageY - 130 }; return ( -
- Your browser does not support the HTML5 canvas tag. + + {' '} + Your browser does not support the HTML5 canvas tag. + {this.menuItems}
- ); } - - -} \ No newline at end of file +} diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx index 8876b4879..c931202f1 100644 --- a/src/client/views/nodes/RadialMenuItem.tsx +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -1,8 +1,8 @@ -import React = require("react"); +import * as React from 'react'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { observer } from "mobx-react"; -import { UndoManager } from "../../util/UndoManager"; +import { observer } from 'mobx-react'; +import { UndoManager } from '../../util/UndoManager'; export interface RadialMenuProps { description: string; @@ -15,17 +15,15 @@ export interface RadialMenuProps { selected: number; } - @observer export class RadialMenuItem extends React.Component { - componentDidMount = () => { this.setcircle(); - } + }; componentDidUpdate = () => { this.setcircle(); - } + }; handleEvent = async (e: React.PointerEvent) => { this.props.closeMenu && this.props.closeMenu(); @@ -35,38 +33,36 @@ export class RadialMenuItem extends React.Component { } await this.props.event({ x: e.clientX, y: e.clientY }); batch && batch.end(); - } - + }; setcircle() { let circlemin = 0; let circlemax = 1; - this.props.min ? circlemin = this.props.min : null; - this.props.max ? circlemax = this.props.max : null; - if (document.getElementById("myCanvas") !== null) { - const c: any = document.getElementById("myCanvas"); - let color = "white"; + this.props.min ? (circlemin = this.props.min) : null; + this.props.max ? (circlemax = this.props.max) : null; + if (document.getElementById('myCanvas') !== null) { + const c: any = document.getElementById('myCanvas'); + let color = 'white'; switch (circlemin % 3) { case 1: - color = "#c2c2c5"; + color = '#c2c2c5'; break; case 0: - color = "#f1efeb"; + color = '#f1efeb'; break; case 2: - color = "lightgray"; + color = 'lightgray'; break; } if (circlemax % 3 === 1 && circlemin === circlemax - 1) { - color = "#c2c2c5"; + color = '#c2c2c5'; } if (this.props.selected === this.props.min) { - color = "#808080"; - + color = '#808080'; } if (c.getContext) { - const ctx = c.getContext("2d"); + const ctx = c.getContext('2d'); ctx.beginPath(); ctx.arc(150, 150, 150, (circlemin / circlemax) * 2 * Math.PI, ((circlemin + 1) / circlemax) * 2 * Math.PI); ctx.arc(150, 150, 50, ((circlemin + 1) / circlemax) * 2 * Math.PI, (circlemin / circlemax) * 2 * Math.PI, true); @@ -79,35 +75,36 @@ export class RadialMenuItem extends React.Component { calculatorx() { let circlemin = 0; let circlemax = 1; - this.props.min ? circlemin = this.props.min : null; - this.props.max ? circlemax = this.props.max : null; - const avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2; + this.props.min ? (circlemin = this.props.min) : null; + this.props.max ? (circlemax = this.props.max) : null; + const avg = (circlemin / circlemax + (circlemin + 1) / circlemax) / 2; const degrees = 360 * avg; - const x = 100 * Math.cos(degrees * Math.PI / 180); - const y = -125 * Math.sin(degrees * Math.PI / 180); + const x = 100 * Math.cos((degrees * Math.PI) / 180); + const y = -125 * Math.sin((degrees * Math.PI) / 180); return x; } calculatory() { - let circlemin = 0; let circlemax = 1; - this.props.min ? circlemin = this.props.min : null; - this.props.max ? circlemax = this.props.max : null; - const avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2; + this.props.min ? (circlemin = this.props.min) : null; + this.props.max ? (circlemax = this.props.max) : null; + const avg = (circlemin / circlemax + (circlemin + 1) / circlemax) / 2; const degrees = 360 * avg; - const x = 125 * Math.cos(degrees * Math.PI / 180); - const y = -100 * Math.sin(degrees * Math.PI / 180); + const x = 125 * Math.cos((degrees * Math.PI) / 180); + const y = -100 * Math.sin((degrees * Math.PI) / 180); return y; } - render() { return ( -
- Your browser does not support the HTML5 canvas tag. - +
+ + {' '} + Your browser does not support the HTML5 canvas tag. + +
); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index c2e204eab..7c21b1893 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; // import { Canvas } from '@react-three/fiber'; import { computed, observable, runInAction } from 'mobx'; diff --git a/src/client/views/nodes/ScriptingBox.scss b/src/client/views/nodes/ScriptingBox.scss index 8d76f2b1d..9789da55a 100644 --- a/src/client/views/nodes/ScriptingBox.scss +++ b/src/client/views/nodes/ScriptingBox.scss @@ -32,7 +32,7 @@ .scriptingBox-wrapper { width: 100%; height: 100%; - max-height: calc(100%-30px); + max-height: calc(100% - 30px); display: flex; flex-direction: row; overflow: auto; @@ -42,7 +42,8 @@ overflow: hidden; } - .scriptingBox-textArea, .scriptingBox-textArea-inputs { + .scriptingBox-textArea, + .scriptingBox-textArea-inputs { flex: 70; height: 100%; max-width: 95%; @@ -110,7 +111,7 @@ cursor: pointer; } - .rta__entity>* { + .rta__entity > * { padding-left: 4px; padding-right: 4px; } @@ -125,7 +126,7 @@ .scriptingBox-textArea-inputs { max-width: 100%; height: 40%; - width: 100%; + width: 100%; resize: none; } .scriptingBox-textArea-script { @@ -194,8 +195,8 @@ .scriptingBox-errorMessage { overflow: auto; - background: "red"; - background-color: "red"; + background: 'red'; + background-color: 'red'; height: 45px; } @@ -221,4 +222,4 @@ width: 25%; } } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/TaskCompletedBox.tsx b/src/client/views/nodes/TaskCompletedBox.tsx index 2a3dd8d2d..a17b1dee9 100644 --- a/src/client/views/nodes/TaskCompletedBox.tsx +++ b/src/client/views/nodes/TaskCompletedBox.tsx @@ -1,13 +1,11 @@ -import React = require("react"); -import { observer } from "mobx-react"; -import "./TaskCompletedBox.scss"; -import { observable, action } from "mobx"; -import { Fade } from "@material-ui/core"; - +import * as React from 'react'; +import { observer } from 'mobx-react'; +import './TaskCompletedBox.scss'; +import { observable, action } from 'mobx'; +import { Fade } from '@material-ui/core'; @observer export class TaskCompletionBox extends React.Component<{}> { - @observable public static taskCompleted: boolean = false; @observable public static popupX: number = 500; @observable public static popupY: number = 150; @@ -16,15 +14,20 @@ export class TaskCompletionBox extends React.Component<{}> { @action public static toggleTaskCompleted = () => { TaskCompletionBox.taskCompleted = !TaskCompletionBox.taskCompleted; - } + }; render() { - return -
{TaskCompletionBox.textDisplayed}
-
; + return ( + +
+ {TaskCompletionBox.textDisplayed} +
+
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 0f6c6724a..04780155d 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index b3afe6ba0..d02e5f3e8 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -36,7 +36,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { LinkDocPreview } from './LinkDocPreview'; import { PinProps, PresBox } from './trails'; import './WebBox.scss'; -import React = require('react'); +import * as React from 'react'; const { CreateImage } = require('./WebBoxRenderer'); const _global = (window /* browser */ || global) /* node */ as any; const htmlToText = require('html-to-text'); diff --git a/src/client/views/nodes/formattedText/DashDocCommentView.tsx b/src/client/views/nodes/formattedText/DashDocCommentView.tsx index aa269d8d6..d6b053c8e 100644 --- a/src/client/views/nodes/formattedText/DashDocCommentView.tsx +++ b/src/client/views/nodes/formattedText/DashDocCommentView.tsx @@ -2,7 +2,7 @@ import { TextSelection } from 'prosemirror-state'; import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { DocServer } from '../../../DocServer'; -import React = require('react'); +import * as React from 'react'; // creates an inline comment in a note when '>>' is typed. // the comment sits on the right side of the note and vertically aligns with its anchor in the text. diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 95743a036..4384c8958 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -11,7 +11,7 @@ import { Docs, DocUtils } from '../../../documents/Documents'; import { Transform } from '../../../util/Transform'; import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FormattedTextBox } from './FormattedTextBox'; -import React = require('react'); +import * as React from 'react'; export class DashDocView { dom: HTMLSpanElement; // container for label and value diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index a914084f9..16622c258 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -16,7 +16,7 @@ import { SchemaTableCell } from '../../collections/collectionSchema/SchemaTableC import { OpenWhere } from '../DocumentView'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; -import React = require('react'); +import * as React from 'react'; import { Transform } from '../../../util/Transform'; export class DashFieldView { diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx index 5e62d94c2..85a33614c 100644 --- a/src/client/views/nodes/formattedText/EquationView.tsx +++ b/src/client/views/nodes/formattedText/EquationView.tsx @@ -7,7 +7,7 @@ import { Doc } from '../../../../fields/Doc'; import { StrCast } from '../../../../fields/Types'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; -import React = require('react'); +import * as React from 'react'; export class EquationView { dom: HTMLDivElement; // container for label and value diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 42e8ace6e..2315cdccb 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -72,7 +72,7 @@ import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; import applyDevTools = require('prosemirror-dev-tools'); -import React = require('react'); +import * as React from 'react'; // setting up cors-anywhere server address const translate = setCORS('http://cors-anywhere.herokuapp.com/'); export const GoogleRef = 'googleDocId'; @@ -1954,7 +1954,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - const ComponentTag = tag === CollectionViewType.Freeform ? CollectionFreeFormView : tag === CollectionViewType.Tree ? CollectionTreeView : tag === 'translation' ? FormattedTextBox : CollectionStackingView; + const ComponentTag: any = tag === CollectionViewType.Freeform ? CollectionFreeFormView : tag === CollectionViewType.Tree ? CollectionTreeView : tag === 'translation' ? FormattedTextBox : CollectionStackingView; return ComponentTag === CollectionStackingView ? ( () { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 2303e4126..786988d8b 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx'; diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index f8aebd021..0effb2ccc 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -24,7 +24,7 @@ import { StyleProp } from '../../StyleProvider'; import { PresBox } from './PresBox'; import './PresElementBox.scss'; import { PresMovement } from './PresEnums'; -import React = require('react'); +import * as React from 'react'; /** * This class models the view a document added to presentation will have in the presentation. * It involves some functionality for its buttons and options. diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index d68859e88..35c27d81b 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction } from 'mobx'; diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index e1e87763c..cf19ff6bc 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index 038c45582..cce67fed2 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import './GPTPopup.scss'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 33a336de3..b2373b190 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -23,7 +23,7 @@ import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; import './PDFViewer.scss'; -import React = require('react'); +import * as React from 'react'; const PDFJSViewer = require('pdfjs-dist/web/pdf_viewer'); const pdfjsLib = require('pdfjs-dist'); const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/search/NaviconButton.scss b/src/client/views/search/NaviconButton.scss index 8a70b29de..13d31bbe9 100644 --- a/src/client/views/search/NaviconButton.scss +++ b/src/client/views/search/NaviconButton.scss @@ -1,4 +1,4 @@ -@import "../global/globalCssVariables"; +@import '../global/globalCssVariables'; $height-icon: 15px; $width-line: 30px; @@ -6,7 +6,7 @@ $height-line: 4px; $transition-time: 0.4s; $rotation: 45deg; -$translateY: ($height-icon / 2); +$translateY: calc($height-icon / 2); $translateX: 0; #hamburger-icon { @@ -25,7 +25,7 @@ $translateX: 0; height: $height-line; position: absolute; left: 0; - border-radius: ($height-line / 2); + border-radius: calc($height-line / 2); transition: all $transition-time; -webkit-transition: all $transition-time; -moz-transition: all $transition-time; @@ -66,4 +66,4 @@ $translateX: 0; transform: scale(1.1); -webkit-transform: scale(1.1); -moz-transform: scale(1.1); -} \ No newline at end of file +} diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx index 2139919e0..39e778b76 100644 --- a/src/client/views/selectedDoc/SelectedDocView.tsx +++ b/src/client/views/selectedDoc/SelectedDocView.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ListBox } from 'browndash-components'; import { computed } from 'mobx'; diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index 524492226..093806127 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -11,7 +11,7 @@ import { DocumentView } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './DashWebRTCVideo.scss'; import { hangup, initialize, refreshVideos } from './WebCamLogic'; -import React = require('react'); +import * as React from 'react'; /** * This models the component that will be rendered, that can be used as a doc that will reflect the video cams. diff --git a/src/fields/Schema.ts b/src/fields/Schema.ts index f035eeb0d..f5e64ae1f 100644 --- a/src/fields/Schema.ts +++ b/src/fields/Schema.ts @@ -94,6 +94,7 @@ export function makeStrictInterface(schema: T): (doc: Doc) } export function createSchema(schema: T): T & { proto: ToConstructor } { + return undefined as any; (schema as any).proto = Doc; return schema as any; } diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index da38fcaee..fd119e0bf 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -12,38 +12,38 @@ import { List } from '../fields/List'; import { listSpec } from '../fields/Schema'; import { Cast } from '../fields/Types'; import { Utils } from '../Utils'; -import "./ImageUpload.scss"; +import './ImageUpload.scss'; import { MobileInterface } from './MobileInterface'; -import React = require('react'); +import * as React from 'react'; export interface ImageUploadProps { Document: Doc; // Target document for upload (upload location) } const inputRef = React.createRef(); -const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", "")); +const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', '')); @observer export class Uploader extends React.Component { - @observable error: string = ""; - @observable nm: string = "Choose files"; // Text of 'Choose Files' button - @observable process: string = ""; // Current status of upload + @observable error: string = ''; + @observable nm: string = 'Choose files'; // Text of 'Choose Files' button + @observable process: string = ''; // Current status of upload onClick = async () => { try { const col = this.props.Document; await Docs.Prototypes.initialize(); - const imgPrev = document.getElementById("img_preview"); - this.setOpacity(1, "1"); // Slab 1 + const imgPrev = document.getElementById('img_preview'); + this.setOpacity(1, '1'); // Slab 1 if (imgPrev) { const files: FileList | null = inputRef.current!.files; - this.setOpacity(2, "1"); // Slab 2 + this.setOpacity(2, '1'); // Slab 2 if (files && files.length !== 0) { - this.process = "Uploading Files"; + this.process = 'Uploading Files'; for (let index = 0; index < files.length; ++index) { const file = files[index]; - const res = await Networking.UploadFilesToServer({file}); - this.setOpacity(3, "1"); // Slab 3 + const res = await Networking.UploadFilesToServer({ file }); + this.setOpacity(3, '1'); // Slab 3 // For each item that the user has selected res.map(async ({ result }) => { const name = file.name; @@ -53,19 +53,19 @@ export class Uploader extends React.Component { const path = result.accessPaths.agnostic.client; let doc = null; // Case 1: File is a video - if (file.type === "video/mp4") { + if (file.type === 'video/mp4') { doc = Docs.Create.VideoDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); // Case 2: File is a PDF document - } else if (file.type === "application/pdf") { + } else if (file.type === 'application/pdf') { doc = Docs.Create.PdfDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); // Case 3: File is another document type (most likely Image) } else { doc = Docs.Create.ImageDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); } - this.setOpacity(4, "1"); // Slab 4 - const res = await rp.get(Utils.prepend("/getUserDocumentIds")); + this.setOpacity(4, '1'); // Slab 4 + const res = await rp.get(Utils.prepend('/getUserDocumentIds')); if (!res) { - throw new Error("No user id returned"); + throw new Error('No user id returned'); } const field = await DocServer.GetRefField(JSON.parse(res).userDocumentId); let pending: Opt; @@ -76,19 +76,19 @@ export class Uploader extends React.Component { const data = await Cast(pending.data, listSpec(Doc)); if (data) data.push(doc); else pending.data = new List([doc]); - this.setOpacity(5, "1"); // Slab 5 - this.process = "File " + (index + 1).toString() + " Uploaded"; - this.setOpacity(6, "1"); // Slab 6 + this.setOpacity(5, '1'); // Slab 5 + this.process = 'File ' + (index + 1).toString() + ' Uploaded'; + this.setOpacity(6, '1'); // Slab 6 } - if ((index + 1) === files.length) { - this.process = "Uploads Completed"; - this.setOpacity(7, "1"); // Slab 7 + if (index + 1 === files.length) { + this.process = 'Uploads Completed'; + this.setOpacity(7, '1'); // Slab 7 } }); } // Case in which the user pressed upload and no files were selected } else { - this.process = "No file selected"; + this.process = 'No file selected'; } // Three seconds after upload the menu will reset setTimeout(this.clearUpload, 3000); @@ -96,7 +96,7 @@ export class Uploader extends React.Component { } catch (error) { this.error = JSON.stringify(error); } - } + }; // Updates label after a files is selected (so user knows a file is uploaded) inputLabel = async () => { @@ -105,46 +105,48 @@ export class Uploader extends React.Component { if (files && files.length === 1) { this.nm = files[0].name; } else if (files && files.length > 1) { - this.nm = files.length.toString() + " files selected"; + this.nm = files.length.toString() + ' files selected'; } - } + }; // Loops through load icons, and resets buttons @action clearUpload = () => { for (let i = 1; i < 8; i++) { - this.setOpacity(i, "0.2"); + this.setOpacity(i, '0.2'); } - this.nm = "Choose files"; + this.nm = 'Choose files'; if (inputRef.current) { - inputRef.current.value = ""; + inputRef.current.value = ''; } - this.process = ""; - } + this.process = ''; + }; // Clears the upload and closes the upload menu closeUpload = () => { this.clearUpload(); MobileInterface.Instance.toggleUpload(); - } + }; // Handles the setting of the loading bar setOpacity = (index: number, opacity: string) => { - const slab = document.getElementById("slab" + index); + const slab = document.getElementById('slab' + index); if (slab) slab.style.opacity = opacity; - } + }; // Returns the upload interface for mobile private get uploadInterface() { return (
this.closeUpload()}> - +
- - - + + +
Upload
@@ -167,16 +169,6 @@ export class Uploader extends React.Component { @observable private overlayOpacity = 0.4; render() { - return ( - - ); + return ; } - -} \ No newline at end of file +} diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 6415099fd..2e595e4bc 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { DocServer } from '../client/DocServer'; diff --git a/src/server/DashSession/DashSessionAgent.ts b/src/server/DashSession/DashSessionAgent.ts index 1a5934d8f..2450798aa 100644 --- a/src/server/DashSession/DashSessionAgent.ts +++ b/src/server/DashSession/DashSessionAgent.ts @@ -1,18 +1,18 @@ -import { Email, pathFromRoot } from "../ActionUtilities"; -import { red, yellow, green, cyan } from "colors"; -import { get } from "request-promise"; -import { Utils } from "../../Utils"; -import { WebSocket } from "../websocket"; -import { MessageStore } from "../Message"; -import { launchServer, onWindows } from ".."; -import { readdirSync, statSync, createWriteStream, readFileSync, unlinkSync } from "fs"; -import * as Archiver from "archiver"; -import { resolve } from "path"; -import rimraf = require("rimraf"); -import { AppliedSessionAgent, ExitHandler } from "./Session/agents/applied_session_agent"; -import { ServerWorker } from "./Session/agents/server_worker"; -import { Monitor } from "./Session/agents/monitor"; -import { MessageHandler, ErrorLike } from "./Session/agents/promisified_ipc_manager"; +import { Email, pathFromRoot } from '../ActionUtilities'; +import { red, yellow, green, cyan } from 'colors'; +import { get } from 'request-promise'; +import { Utils } from '../../Utils'; +import { WebSocket } from '../websocket'; +import { MessageStore } from '../Message'; +import { launchServer, onWindows } from '..'; +import { readdirSync, statSync, createWriteStream, readFileSync, unlinkSync } from 'fs'; +import * as Archiver from 'archiver'; +import { resolve } from 'path'; +import * as rimraf from 'rimraf'; +import { AppliedSessionAgent, ExitHandler } from './Session/agents/applied_session_agent'; +import { ServerWorker } from './Session/agents/server_worker'; +import { Monitor } from './Session/agents/monitor'; +import { MessageHandler, ErrorLike } from './Session/agents/promisified_ipc_manager'; /** * If we're the monitor (master) thread, we should launch the monitor logic for the session. @@ -20,9 +20,8 @@ import { MessageHandler, ErrorLike } from "./Session/agents/promisified_ipc_mana * our job should be to run the server. */ export class DashSessionAgent extends AppliedSessionAgent { - - private readonly signature = "-Dash Server Session Manager"; - private readonly releaseDesktop = pathFromRoot("../../Desktop"); + private readonly signature = '-Dash Server Session Manager'; + private readonly releaseDesktop = pathFromRoot('../../Desktop'); /** * The core method invoked when the single master thread is initialized. @@ -31,13 +30,13 @@ export class DashSessionAgent extends AppliedSessionAgent { protected async initializeMonitor(monitor: Monitor): Promise { const sessionKey = Utils.GenerateGuid(); await this.dispatchSessionPassword(sessionKey); - monitor.addReplCommand("pull", [], () => monitor.exec("git pull")); - monitor.addReplCommand("solr", [/start|stop|index/], this.executeSolrCommand); - monitor.addReplCommand("backup", [], this.backup); - monitor.addReplCommand("debug", [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to)); - monitor.on("backup", this.backup); - monitor.on("debug", async ({ to }) => this.dispatchZippedDebugBackup(to)); - monitor.on("delete", WebSocket.doDelete); + monitor.addReplCommand('pull', [], () => monitor.exec('git pull')); + monitor.addReplCommand('solr', [/start|stop|index/], this.executeSolrCommand); + monitor.addReplCommand('backup', [], this.backup); + monitor.addReplCommand('debug', [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to)); + monitor.on('backup', this.backup); + monitor.on('debug', async ({ to }) => this.dispatchZippedDebugBackup(to)); + monitor.on('delete', WebSocket.doDelete); monitor.coreHooks.onCrashDetected(this.dispatchCrashReport); return sessionKey; } @@ -58,13 +57,13 @@ export class DashSessionAgent extends AppliedSessionAgent { private _remoteDebugInstructions: string | undefined; private generateDebugInstructions = (zipName: string, target: string): string => { if (!this._remoteDebugInstructions) { - this._remoteDebugInstructions = readFileSync(resolve(__dirname, "./templates/remote_debug_instructions.txt"), { encoding: "utf8" }); + this._remoteDebugInstructions = readFileSync(resolve(__dirname, './templates/remote_debug_instructions.txt'), { encoding: 'utf8' }); } return this._remoteDebugInstructions .replace(/__zipname__/, zipName) .replace(/__target__/, target) .replace(/__signature__/, this.signature); - } + }; /** * Prepares the body of the email with information regarding a crash event. @@ -72,12 +71,12 @@ export class DashSessionAgent extends AppliedSessionAgent { private _crashInstructions: string | undefined; private generateCrashInstructions({ name, message, stack }: ErrorLike): string { if (!this._crashInstructions) { - this._crashInstructions = readFileSync(resolve(__dirname, "./templates/crash_instructions.txt"), { encoding: "utf8" }); + this._crashInstructions = readFileSync(resolve(__dirname, './templates/crash_instructions.txt'), { encoding: 'utf8' }); } return this._crashInstructions - .replace(/__name__/, name || "[no error name found]") - .replace(/__message__/, message || "[no error message found]") - .replace(/__stack__/, stack || "[no error stack found]") + .replace(/__name__/, name || '[no error name found]') + .replace(/__message__/, message || '[no error message found]') + .replace(/__stack__/, stack || '[no error stack found]') .replace(/__signature__/, this.signature); } @@ -88,23 +87,19 @@ export class DashSessionAgent extends AppliedSessionAgent { private dispatchSessionPassword = async (sessionKey: string): Promise => { const { mainLog } = this.sessionMonitor; const { notificationRecipient } = DashSessionAgent; - mainLog(green("dispatching session key...")); + mainLog(green('dispatching session key...')); const error = await Email.dispatch({ to: notificationRecipient, - subject: "Dash Release Session Admin Authentication Key", - content: [ - `Here's the key for this session (started @ ${new Date().toUTCString()}):`, - sessionKey, - this.signature - ].join("\n\n") + subject: 'Dash Release Session Admin Authentication Key', + content: [`Here's the key for this session (started @ ${new Date().toUTCString()}):`, sessionKey, this.signature].join('\n\n'), }); if (error) { this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} (${yellow(error.message)})`)); - mainLog(red("distribution of session key experienced errors")); + mainLog(red('distribution of session key experienced errors')); } else { - mainLog(green("successfully distributed session key to recipients")); + mainLog(green('successfully distributed session key to recipients')); } - } + }; /** * This sends an email with the generated crash report. @@ -114,37 +109,37 @@ export class DashSessionAgent extends AppliedSessionAgent { const { notificationRecipient } = DashSessionAgent; const error = await Email.dispatch({ to: notificationRecipient, - subject: "Dash Web Server Crash", - content: this.generateCrashInstructions(crashCause) + subject: 'Dash Web Server Crash', + content: this.generateCrashInstructions(crashCause), }); if (error) { this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} ${yellow(`(${error.message})`)}`)); - mainLog(red("distribution of crash notification experienced errors")); + mainLog(red('distribution of crash notification experienced errors')); } else { - mainLog(green("successfully distributed crash notification to recipients")); + mainLog(green('successfully distributed crash notification to recipients')); } - } + }; /** - * Logic for interfacing with Solr. Either starts it, + * Logic for interfacing with Solr. Either starts it, * stops it, or rebuilds its indices. */ private executeSolrCommand = async (args: string[]): Promise => { const { exec, mainLog } = this.sessionMonitor; const action = args[0]; - if (action === "index") { - exec("npx ts-node ./updateSearch.ts", { cwd: pathFromRoot("./src/server") }); + if (action === 'index') { + exec('npx ts-node ./updateSearch.ts', { cwd: pathFromRoot('./src/server') }); } else { - const command = `${onWindows ? "solr.cmd" : "solr"} ${args[0] === "start" ? "start" : "stop -p 8983"}`; - await exec(command, { cwd: "./solr-8.3.1/bin" }); + const command = `${onWindows ? 'solr.cmd' : 'solr'} ${args[0] === 'start' ? 'start' : 'stop -p 8983'}`; + await exec(command, { cwd: './solr-8.3.1/bin' }); try { - await get("http://localhost:8983"); - mainLog(green("successfully connected to 8983 after running solr initialization")); + await get('http://localhost:8983'); + mainLog(green('successfully connected to 8983 after running solr initialization')); } catch { - mainLog(red("unable to connect at 8983 after running solr initialization")); + mainLog(red('unable to connect at 8983 after running solr initialization')); } } - } + }; /** * Broadcast to all clients that their connection @@ -153,16 +148,16 @@ export class DashSessionAgent extends AppliedSessionAgent { private notifyClient: ExitHandler = reason => { const { _socket } = WebSocket; if (_socket) { - const message = typeof reason === "boolean" ? (reason ? "exit" : "temporary") : "crash"; + const message = typeof reason === 'boolean' ? (reason ? 'exit' : 'temporary') : 'crash'; Utils.Emit(_socket, MessageStore.ConnectionTerminated, message); } - } + }; /** * Performs a backup of the database, saved to the desktop subdirectory. * This should work as is only on our specific release server. */ - private backup = async (): Promise => this.sessionMonitor.exec("backup.bat", { cwd: this.releaseDesktop }); + private backup = async (): Promise => this.sessionMonitor.exec('backup.bat', { cwd: this.releaseDesktop }); /** * Compress either a brand new backup or the most recent backup and send it @@ -175,15 +170,17 @@ export class DashSessionAgent extends AppliedSessionAgent { try { // if desired, complete an immediate backup to send await this.backup(); - mainLog("backup complete"); + mainLog('backup complete'); const backupsDirectory = `${this.releaseDesktop}/backups`; // sort all backups by their modified time, and choose the most recent one - const target = readdirSync(backupsDirectory).map(filename => ({ - modifiedTime: statSync(`${backupsDirectory}/${filename}`).mtimeMs, - filename - })).sort((a, b) => b.modifiedTime - a.modifiedTime)[0].filename; + const target = readdirSync(backupsDirectory) + .map(filename => ({ + modifiedTime: statSync(`${backupsDirectory}/${filename}`).mtimeMs, + filename, + })) + .sort((a, b) => b.modifiedTime - a.modifiedTime)[0].filename; mainLog(`targeting ${target}...`); // create a zip file and to it, write the contents of the backup directory @@ -202,28 +199,25 @@ export class DashSessionAgent extends AppliedSessionAgent { to, subject: `Remote debug: compressed backup of ${target}...`, content: this.generateDebugInstructions(zipName, target), - attachments: [{ filename: zipName, path: zipPath }] + attachments: [{ filename: zipName, path: zipPath }], }); - // since this is intended to be a zero-footprint operation, clean up + // since this is intended to be a zero-footprint operation, clean up // by unlinking both the backup generated earlier in the function and the compressed zip file. // to generate a persistent backup, just run backup. unlinkSync(zipPath); rimraf.sync(targetPath); // indicate success or failure - mainLog(`${error === null ? green("successfully dispatched") : red("failed to dispatch")} ${zipName} to ${cyan(to)}`); + mainLog(`${error === null ? green('successfully dispatched') : red('failed to dispatch')} ${zipName} to ${cyan(to)}`); error && mainLog(red(error.message)); } catch (error: any) { - mainLog(red("unable to dispatch zipped backup...")); + mainLog(red('unable to dispatch zipped backup...')); mainLog(red(error.message)); } } - } export namespace DashSessionAgent { - - export const notificationRecipient = "browndashptc@gmail.com"; - + export const notificationRecipient = 'browndashptc@gmail.com'; } diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 2053ae448..fa29cb7c1 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -14,8 +14,8 @@ import { createIfNotExists } from './ActionUtilities'; import { clientPathToFile, Directory, pathToDirectory, serverPathToFile } from './ApiManagers/UploadManager'; import { resolvedServerUrl } from './server_Initialization'; import { AcceptableMedia, Upload } from './SharedMediaTypes'; -import request = require('request-promise'); -import formidable = require('formidable'); +import * as request from 'request-promise'; +import * as formidable from 'formidable'; import { AzureManager } from './ApiManagers/AzureManager'; import axios from 'axios'; const spawn = require('child_process').spawn; @@ -366,7 +366,7 @@ export namespace DashUploadUtils { } export interface ImageResizer { - width?: any; // sharp.Sharp; + width: number; suffix: SizeSuffix; } @@ -622,7 +622,7 @@ export namespace DashUploadUtils { */ export function imageResampleSizes(ext: string): DashUploadUtils.ImageResizer[] { return [ - { suffix: SizeSuffix.Original }, + { suffix: SizeSuffix.Original, width: 0 }, ...[...(AcceptableMedia.imageFormats.includes(ext.toLowerCase()) ? Object.values(DashUploadUtils.Sizes) : [])].map(({ suffix, width }) => ({ width, suffix, diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts index 23e4680fd..f5189ddf1 100644 --- a/src/typings/index.d.ts +++ b/src/typings/index.d.ts @@ -13,6 +13,10 @@ declare module 'reveal'; declare module 'react-reveal'; declare module 'react-reveal/makeCarousel'; declare module 'react-resizable-rotatable-draggable'; +declare module 'socket.io-parser' { + type Encoder = any; + type Decoder = any; +} declare module '@react-pdf/renderer' { import * as React from 'react'; diff --git a/tsconfig.json b/tsconfig.json index f1b275954..1e8934ee8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "ES2017", "downlevelIteration": true, "removeComments": true, "experimentalDecorators": true, @@ -11,10 +11,11 @@ "allowJs": true, "sourceMap": true, "outDir": "dist", - "lib": ["dom", "es2015"], + "lib": ["dom", "es2017"], "typeRoots": ["node_modules/@types", "./src/typings"], "types": ["youtube", "node"], - "resolveJsonModule": true + "resolveJsonModule": true, + "moduleResolution": "node" }, // "exclude": [ // "node_modules", diff --git a/webpack.config.js b/webpack.config.js index 01625988c..098604f1f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,23 +1,28 @@ +/* eslint-disable node/no-unpublished-require */ const path = require('path'); const webpack = require('webpack'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const { parsed } = require('dotenv').config(); const plugins = [ - new CopyWebpackPlugin([ - { - from: 'deploy', - to: path.join(__dirname, 'build'), - }, - ]), + // new CopyWebpackPlugin({ + // patterns: [ + // { + // from: 'deploy', + // to: path.join(__dirname, 'build'), + // }, + // ], + // }), new HtmlWebpackPlugin({ title: 'Caching', }), new ForkTsCheckerWebpackPlugin({ tslint: true, - // memoryLimit: 4096, + memoryLimit: 4096, useTypescriptIncrementalApi: true, + tslintAutoFix: true, }), new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }), new webpack.ProvidePlugin({ process: 'process/browser' }), @@ -26,12 +31,12 @@ const plugins = [ function transferEnvironmentVariables() { const prefix = '_CLIENT_'; - const { parsed } = require('dotenv').config(); if (!parsed) { return; } const resolvedClientSide = Object.keys(parsed).reduce((mapping, envKey) => { if (envKey.startsWith(prefix)) { + // eslint-disable-next-line mapping[`process.env.${envKey.replace(prefix, '')}`] = JSON.stringify(parsed[envKey]); } return mapping; -- cgit v1.2.3-70-g09d2 From 380ee1acac1c0b7972d7d423cf804af146dc0edf Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 10 Dec 2023 20:19:27 -0500 Subject: massive changes to use mobx 6 which means not accessing props directly in @computed functions. --- package-lock.json | 2762 +++++++++++++++++--- package.json | 13 +- src/.babelrc | 3 + src/Utils.ts | 7 + src/client/DocServer.ts | 2 +- src/client/documents/DocumentTypes.ts | 1 - src/client/documents/Documents.ts | 13 +- src/client/util/DocumentManager.ts | 11 +- .../util/Import & Export/DirectoryImportBox.tsx | 3 +- src/client/util/LinkManager.ts | 14 +- src/client/util/RTFMarkup.tsx | 2 +- src/client/util/SelectionManager.ts | 20 +- src/client/util/ServerStats.tsx | 6 +- src/client/util/SettingsManager.tsx | 8 +- src/client/util/SharingManager.tsx | 4 +- src/client/util/SnappingManager.ts | 2 +- src/client/views/AntimodeMenu.tsx | 19 +- src/client/views/AudioWaveform.scss | 17 - src/client/views/AudioWaveform.tsx | 117 - src/client/views/ContextMenu.tsx | 99 +- src/client/views/ContextMenuItem.tsx | 20 +- src/client/views/DocComponent.tsx | 61 +- src/client/views/DocumentButtonBar.tsx | 61 +- src/client/views/DocumentDecorations.tsx | 74 +- src/client/views/EditableView.tsx | 111 +- src/client/views/InkStrokeProperties.ts | 2 +- src/client/views/InkingStroke.tsx | 4 +- src/client/views/MainView.tsx | 19 +- src/client/views/MainViewModal.tsx | 2 - src/client/views/MarqueeAnnotator.tsx | 19 +- src/client/views/PreviewCursor.tsx | 135 +- src/client/views/PropertiesView.tsx | 53 +- src/client/views/StyleProvider.tsx | 4 +- .../views/collections/CollectionDockingView.tsx | 45 +- .../collections/CollectionMasonryViewFieldRow.tsx | 101 +- src/client/views/collections/CollectionMenu.tsx | 45 +- .../views/collections/CollectionNoteTakingView.tsx | 1 - .../views/collections/CollectionPileView.tsx | 2 +- .../collections/CollectionStackedTimeline.tsx | 217 +- .../views/collections/CollectionStackingView.tsx | 187 +- .../CollectionStackingViewFieldColumn.tsx | 139 +- src/client/views/collections/CollectionSubView.tsx | 92 +- .../views/collections/CollectionTreeView.tsx | 192 +- src/client/views/collections/CollectionView.tsx | 53 +- src/client/views/collections/TabDocView.tsx | 91 +- src/client/views/collections/TreeView.tsx | 505 ++-- .../CollectionFreeFormInfoState.tsx | 16 +- .../CollectionFreeFormInfoUI.tsx | 38 +- .../CollectionFreeFormLinkView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 376 +-- .../collections/collectionFreeForm/MarqueeView.tsx | 142 +- .../collectionGrid/CollectionGridView.tsx | 2 - .../collectionLinear/CollectionLinearView.tsx | 44 +- .../CollectionMulticolumnView.tsx | 1 - .../CollectionMultirowView.tsx | 1 - .../collectionSchema/CollectionSchemaView.tsx | 10 +- .../collectionSchema/SchemaColumnHeader.tsx | 2 +- .../collections/collectionSchema/SchemaRowBox.tsx | 4 +- .../collectionSchema/SchemaTableCell.tsx | 141 +- src/client/views/global/globalScripts.ts | 8 +- src/client/views/linking/LinkMenu.tsx | 8 +- src/client/views/linking/LinkMenuItem.tsx | 96 +- src/client/views/nodes/AudioBox.tsx | 75 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 109 +- src/client/views/nodes/ColorBox.scss | 22 - src/client/views/nodes/ColorBox.tsx | 88 - .../views/nodes/DataVizBox/components/TableBox.tsx | 4 +- src/client/views/nodes/DocumentContentsView.tsx | 60 +- src/client/views/nodes/DocumentLinksButton.tsx | 106 +- src/client/views/nodes/DocumentView.tsx | 419 +-- src/client/views/nodes/EquationBox.tsx | 34 +- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 32 +- src/client/views/nodes/FunctionPlotBox.tsx | 37 +- src/client/views/nodes/ImageBox.tsx | 198 +- src/client/views/nodes/KeyValueBox.tsx | 38 +- src/client/views/nodes/KeyValuePair.tsx | 37 +- src/client/views/nodes/LabelBox.tsx | 29 +- src/client/views/nodes/LinkBox.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 4 +- src/client/views/nodes/LoadingBox.tsx | 14 +- src/client/views/nodes/MapBox/MapBox.tsx | 84 +- src/client/views/nodes/MapBox/MapBox2.tsx | 2 +- src/client/views/nodes/MapBox/MapPushpinBox.tsx | 14 +- src/client/views/nodes/PDFBox.tsx | 95 +- src/client/views/nodes/ScreenshotBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 123 +- src/client/views/nodes/WebBox.tsx | 4 +- src/client/views/nodes/audio/AudioWaveform.scss | 17 + src/client/views/nodes/audio/AudioWaveform.tsx | 127 + src/client/views/nodes/audio/WaveCanvas.tsx | 100 + .../views/nodes/formattedText/DashDocView.tsx | 2 +- .../views/nodes/formattedText/DashFieldView.tsx | 14 +- .../views/nodes/formattedText/EquationEditor.scss | 468 ++++ .../views/nodes/formattedText/EquationEditor.tsx | 8 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 213 +- .../views/nodes/formattedText/RichTextMenu.tsx | 48 +- src/client/views/nodes/trails/PresBox.tsx | 61 +- src/client/views/nodes/trails/PresElementBox.tsx | 64 +- src/client/views/pdf/AnchorMenu.tsx | 24 +- src/client/views/pdf/PDFViewer.tsx | 151 +- src/client/views/topbar/TopBar.tsx | 1 - src/fields/Doc.ts | 40 +- src/fields/List.ts | 5 +- src/fields/util.ts | 2 +- src/server/ApiManagers/GooglePhotosManager.ts | 155 +- src/server/DashUploadUtils.ts | 27 +- tsconfig.json | 2 +- webpack.config.js | 7 +- 108 files changed, 6103 insertions(+), 3316 deletions(-) create mode 100644 src/.babelrc delete mode 100644 src/client/views/AudioWaveform.scss delete mode 100644 src/client/views/AudioWaveform.tsx delete mode 100644 src/client/views/nodes/ColorBox.scss delete mode 100644 src/client/views/nodes/ColorBox.tsx create mode 100644 src/client/views/nodes/audio/AudioWaveform.scss create mode 100644 src/client/views/nodes/audio/AudioWaveform.tsx create mode 100644 src/client/views/nodes/audio/WaveCanvas.tsx create mode 100644 src/client/views/nodes/formattedText/EquationEditor.scss (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/package-lock.json b/package-lock.json index 8cbd29629..9afc22828 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "1.0.0", "dependencies": { "@azure/storage-blob": "^12.17.0", + "@babel/preset-env": "^7.23.5", + "@babel/preset-react": "^7.23.3", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@ffmpeg/core": "0.12.4", @@ -41,6 +43,7 @@ "async": "^3.2.5", "axios": "^1.6.2", "babel": "^6.23.0", + "babel-loader": "^9.1.3", "bcrypt-nodejs": "0.0.3", "bezier-curve": "^1.0.0", "bezier-js": "^6.1.4", @@ -55,7 +58,6 @@ "canvas": "^2.11.2", "chart.js": "^4.4.0", "child_process": "^1.0.2", - "chrome": "^0.1.0", "class-transformer": "^0.5.1", "color": "^4.2.3", "colors": "^1.4.0", @@ -105,6 +107,7 @@ "image-size": "^1.0.2", "image-size-stream": "^1.1.0", "jimp": "^0.22.10", + "jpeg-autorotate": "^9.0.0", "jquery": "^3.7.1", "js-datepicker": "^5.18.2", "jsonschema": "^1.4.1", @@ -114,9 +117,9 @@ "md5-file": "^5.0.0", "memorystream": "^0.3.1", "mobile-detect": "^1.4.5", - "mobx": "^5.15.7", - "mobx-react": "^5.4.4", - "mobx-utils": "^5.6.2", + "mobx": "^6.12.0", + "mobx-react": "^9.1.0", + "mobx-utils": "^6.0.8", "mongodb": "^6.3.0", "mongoose": "^8.0.2", "node-stream-zip": "^1.15.0", @@ -151,7 +154,6 @@ "raw-loader": "^4.0.2", "rc-switch": "^4.1.0", "react": "^18.2.0", - "react-audio-waveform": "0.0.5", "react-autosuggest": "^10.1.0", "react-color": "^2.19.3", "react-compound-slider": "^3.4.0", @@ -164,7 +166,6 @@ "react-markdown": "^9.0.1", "react-measure": "^2.5.2", "react-resizable": "^3.0.5", - "react-reveal": "^1.2.2", "react-select": "^5.8.0", "readline": "^1.3.0", "recharts": "^2.10.3", @@ -288,271 +289,1867 @@ "node": ">=0.10.0" } }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@azure/abort-controller": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", "dependencies": { - "tslib": "^2.2.0" + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz", + "integrity": "sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-http": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.2.tgz", + "integrity": "sha512-o1wR9JrmoM0xEAa0Ue7Sp8j+uJvmqYaGoHOCT5qaVYmvgmnZDC0OvQimPA/JR3u77Sz6D1y3Xmk1y69cDU9q9A==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-tracing": "1.0.0-preview.13", + "@azure/core-util": "^1.1.1", + "@azure/logger": "^1.0.0", + "@types/node-fetch": "^2.5.0", + "@types/tunnel": "^0.0.3", + "form-data": "^4.0.0", + "node-fetch": "^2.6.7", + "process": "^0.11.10", + "tslib": "^2.2.0", + "tunnel": "^0.0.6", + "uuid": "^8.3.0", + "xml2js": "^0.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/core-http/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@azure/core-http/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@azure/core-lro": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.3.tgz", + "integrity": "sha512-ubkOf2YCnVtq7KqEJQqAI8dDD5rH1M6OP5kW0KO/JQyTaxLA0N0pjFWvvaysCj9eHMNBcuuoZXhhl0ypjod2DA==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-util": "^1.2.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/core-paging": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.5.0.tgz", + "integrity": "sha512-zqWdVIt+2Z+3wqxEOGzR5hXFZ8MGKK52x4vFLw8n58pR6ZfKRx3EXYTxTaYxYHc/PexPUTyimcTWFJbji9Z6Iw==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.0.0-preview.13", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz", + "integrity": "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==", + "dependencies": { + "@opentelemetry/api": "^1.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.3.2.tgz", + "integrity": "sha512-2bECOUh88RvL1pMZTcc6OzfobBeWDBf5oBbhjIhT1MV9otMVWCzpOJkkiKtrnO88y5GGBelgY8At73KGAdbkeQ==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.4.tgz", + "integrity": "sha512-ustrPY8MryhloQj7OWGe+HrYx+aoiOxzbXTtgblbV3xwCqpzUK36phH3XNHQKj3EPonyFUuDTfR3qFhTEAuZEg==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/storage-blob": { + "version": "12.17.0", + "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.17.0.tgz", + "integrity": "sha512-sM4vpsCpcCApagRW5UIjQNlNylo02my2opgp0Emi8x888hZUvJ3dN69Oq20cEGXkMUWnoCrBaB0zyS3yeB87sQ==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-http": "^3.0.0", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-tracing": "1.0.0-preview.13", + "@azure/logger": "^1.0.0", + "events": "^3.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", + "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.5", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "peer": true + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "peer": true + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "dependencies": { + "@babel/types": "^7.23.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.5.tgz", + "integrity": "sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", + "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", + "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", + "peer": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz", + "integrity": "sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz", + "integrity": "sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz", + "integrity": "sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz", + "integrity": "sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { - "node": ">=12.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@azure/core-auth": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz", - "integrity": "sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "tslib": "^2.2.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { - "node": ">=12.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@azure/core-http": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.2.tgz", - "integrity": "sha512-o1wR9JrmoM0xEAa0Ue7Sp8j+uJvmqYaGoHOCT5qaVYmvgmnZDC0OvQimPA/JR3u77Sz6D1y3Xmk1y69cDU9q9A==", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-tracing": "1.0.0-preview.13", - "@azure/core-util": "^1.1.1", - "@azure/logger": "^1.0.0", - "@types/node-fetch": "^2.5.0", - "@types/tunnel": "^0.0.3", - "form-data": "^4.0.0", - "node-fetch": "^2.6.7", - "process": "^0.11.10", - "tslib": "^2.2.0", - "tunnel": "^0.0.6", - "uuid": "^8.3.0", - "xml2js": "^0.5.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@azure/core-http/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">= 6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@azure/core-http/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@azure/core-lro": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.3.tgz", - "integrity": "sha512-ubkOf2YCnVtq7KqEJQqAI8dDD5rH1M6OP5kW0KO/JQyTaxLA0N0pjFWvvaysCj9eHMNBcuuoZXhhl0ypjod2DA==", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-util": "^1.2.0", - "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@azure/core-paging": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.5.0.tgz", - "integrity": "sha512-zqWdVIt+2Z+3wqxEOGzR5hXFZ8MGKK52x4vFLw8n58pR6ZfKRx3EXYTxTaYxYHc/PexPUTyimcTWFJbji9Z6Iw==", + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz", + "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==", "dependencies": { - "tslib": "^2.2.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@azure/core-tracing": { - "version": "1.0.0-preview.13", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz", - "integrity": "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==", + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", "dependencies": { - "@opentelemetry/api": "^1.0.1", - "tslib": "^2.2.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" }, "engines": { - "node": ">=12.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@azure/core-util": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.3.2.tgz", - "integrity": "sha512-2bECOUh88RvL1pMZTcc6OzfobBeWDBf5oBbhjIhT1MV9otMVWCzpOJkkiKtrnO88y5GGBelgY8At73KGAdbkeQ==", + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "tslib": "^2.2.0" + "@babel/plugin-transform-react-jsx": "^7.22.5" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@azure/logger": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.4.tgz", - "integrity": "sha512-ustrPY8MryhloQj7OWGe+HrYx+aoiOxzbXTtgblbV3xwCqpzUK36phH3XNHQKj3EPonyFUuDTfR3qFhTEAuZEg==", + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz", + "integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==", "dependencies": { - "tslib": "^2.2.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@azure/storage-blob": { - "version": "12.17.0", - "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.17.0.tgz", - "integrity": "sha512-sM4vpsCpcCApagRW5UIjQNlNylo02my2opgp0Emi8x888hZUvJ3dN69Oq20cEGXkMUWnoCrBaB0zyS3yeB87sQ==", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-http": "^3.0.0", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.1.1", - "@azure/core-tracing": "1.0.0-preview.13", - "@azure/logger": "^1.0.0", - "events": "^3.0.0", - "tslib": "^2.2.0" + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/generator": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", - "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", "dependencies": { - "@babel/types": "^7.23.5", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/parser": { + "node_modules/@babel/preset-env": { "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", - "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.5.tgz", + "integrity": "sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A==", + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.4", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.5", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.3", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { - "parser": "bin/babel-parser.js" + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz", + "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-transform-react-display-name": "^7.23.3", + "@babel/plugin-transform-react-jsx": "^7.22.15", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.23.3" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, "node_modules/@babel/runtime": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", @@ -3215,9 +4812,9 @@ } }, "node_modules/@types/react": { - "version": "18.2.42", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.42.tgz", - "integrity": "sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA==", + "version": "18.2.43", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.43.tgz", + "integrity": "sha512-nvOV01ZdBdd/KW6FahSbcNplt2jCJfyWdTos61RYHV+FVv5L/g9AOX1bmbVcWcLFL8+KHQfh1zVIQrud6ihyQA==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4231,6 +5828,23 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" }, + "node_modules/array-batcher/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/array-batcher/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/array-batcher/node_modules/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", @@ -4306,6 +5920,15 @@ "node": ">=6" } }, + "node_modules/array-batcher/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", @@ -4422,13 +6045,13 @@ } }, "node_modules/array.prototype.reduce": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", - "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.6.tgz", + "integrity": "sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-array-method-boxes-properly": "^1.0.0", "is-string": "^1.0.7" }, @@ -4765,6 +6388,115 @@ "node": ">=4" } }, + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-loader/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/babel-loader/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/babel-loader/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/babel-loader/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", + "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.3", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz", + "integrity": "sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.3", + "core-js-compat": "^3.33.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", + "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.3" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -8037,9 +9769,9 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" }, "node_modules/browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "funding": [ { "type": "opencollective", @@ -8055,10 +9787,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", - "update-browserslist-db": "^1.0.11" + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -8268,11 +10000,11 @@ } }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", "engines": { - "node": ">=6" + "node": ">=4" } }, "node_modules/camelize": { @@ -8284,9 +10016,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001514", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001514.tgz", - "integrity": "sha512-ENcIpYBmwAAOm/V2cXgM7rZUrKKaqisZl4ZAI520FIkqGXUxJjmaIssbRW5HVVR5tyV6ygTLIm15aU8LUmQSaQ==", + "version": "1.0.30001566", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", + "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", "funding": [ { "type": "opencollective", @@ -8479,18 +10211,6 @@ "node": ">=10" } }, - "node_modules/chrome": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chrome/-/chrome-0.1.0.tgz", - "integrity": "sha512-6KYl20U4Taj6YipylsWr2etUvp9AElJKfGNSBmyGTymYmancnOb041ZNadolEZi2nboLXH7jMSqUmm4kpuTzfg==", - "dependencies": { - "exeq": "^2.2.0", - "plist": "^1.1.0" - }, - "bin": { - "chrome": "index.js" - } - }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -8583,22 +10303,6 @@ "yargs-parser": "^7.0.0" } }, - "node_modules/cliss/node_modules/camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/cliss/node_modules/yargs-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", - "integrity": "sha512-WhzC+xgstid9MbVUktco/bf+KJG+Uu6vMX0LN1sLJvwmbCQVxb4D8LzogobonKycNasCZLdOzTAk1SK7+K7swg==", - "dependencies": { - "camelcase": "^4.1.0" - } - }, "node_modules/cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -8793,6 +10497,11 @@ "node": ">= 12" } }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, "node_modules/component-emitter": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", @@ -9025,14 +10734,6 @@ "node": ">= 0.10" } }, - "node_modules/cookie-session/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/cookie-session/node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -9087,6 +10788,18 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-js-compat": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.34.0.tgz", + "integrity": "sha512-4ZIyeNbW/Cn1wkMMDy+mvrRUxrwFNjKwbhCfQpDd+eLgYipDqp8oGFGtLmhh18EDPKA0g3VUBYOxQGGwvWLVpA==", + "dependencies": { + "browserslist": "^4.22.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-js-pure": { "version": "3.28.0", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.28.0.tgz", @@ -9439,9 +11152,9 @@ } }, "node_modules/csv-stringify": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.4.4.tgz", - "integrity": "sha512-NDshLupGa7gp4UG4sSNIqwYJqgSwvds0SvENntxoVoVvTzXcrHvd5gG2MWpbRpSNvk59dlmIe1IwNvSxN4IVmg==" + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.4.5.tgz", + "integrity": "sha512-SPu1Vnh8U5EnzpNOi1NDBL5jU5Rx7DVHr15DNg9LXDTAbQlAVAmEbVt16wZvEW9Fu9Qt4Ji8kmeCJ2B1+4rFTQ==" }, "node_modules/custom-event": { "version": "1.0.1", @@ -9912,10 +11625,9 @@ } }, "node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dependencies": { "ms": "^2.1.1" } @@ -9923,7 +11635,7 @@ "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "engines": { "node": ">=0.10.0" } @@ -10093,18 +11805,6 @@ "node": ">=10.17.0" } }, - "node_modules/default-gateway/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/default-gateway/node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -10756,9 +12456,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "node_modules/electron-to-chromium": { - "version": "1.4.454", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.454.tgz", - "integrity": "sha512-pmf1rbAStw8UEQ0sr2cdJtWl48ZMuPD9Sto8HVQOq9vx9j2WgDEN6lYoaqFvqEHYOmGA9oRGn7LqWI9ta0YugQ==" + "version": "1.4.609", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.609.tgz", + "integrity": "sha512-ihiCP7PJmjoGNuLpl7TjNA8pCQWu09vGyjlPYw1Rqww4gvNuCcmvl+44G+2QyJ6S2K4o+wbTS++Xz0YN8Q9ERw==" }, "node_modules/emoji-regex": { "version": "7.0.3", @@ -11957,15 +13657,6 @@ "resolve": "^1.22.4" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/eslint-module-utils": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", @@ -11983,15 +13674,6 @@ } } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/eslint-plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz", @@ -12081,15 +13763,6 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -12840,18 +14513,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/exeq": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/exeq/-/exeq-2.4.0.tgz", - "integrity": "sha1-Td8qaEZIxCeteZNJzzO9dTWPiEo=", - "dependencies": { - "bluebird": "^3.0.3", - "native-or-bluebird": "^1.2.0" - }, - "engines": { - "node": ">= 0.10.0" - } - }, "node_modules/exif": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/exif/-/exif-0.6.0.tgz", @@ -13491,6 +15152,111 @@ "traverse-chain": "~0.1.0" } }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/find-in-files": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/find-in-files/-/find-in-files-0.5.0.tgz", @@ -14140,9 +15906,9 @@ } }, "node_modules/function-plot": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/function-plot/-/function-plot-1.23.3.tgz", - "integrity": "sha512-YvV517ZNrc93SBlLux3LfNZUEil7DiZGHerKGk5tU/iqIzFYedyw3u7ZeAcrll3qzhKTs84M8XxUiESE7Mlzdw==", + "version": "1.23.4", + "resolved": "https://registry.npmjs.org/function-plot/-/function-plot-1.23.4.tgz", + "integrity": "sha512-CMu6k8MDPpOOvnFBRhahtqm0UKzxhxxFYkp1p5Xd06iTDenhpvVh1s0/uR6GTymJX8Hdgwr4iWsEUWXOhgtJUQ==", "dependencies": { "built-in-math-eval": "^0.3.0", "clamp": "^1.0.1", @@ -14154,6 +15920,7 @@ "d3-selection": "^3.0.0", "d3-shape": "^3.1.0", "d3-zoom": "^3.0.0", + "events": "^3.3.0", "interval-arithmetic-eval": "^0.5.1" } }, @@ -14305,32 +16072,48 @@ "node": ">= 14" } }, - "node_modules/gaxios/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gaxios/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/gcp-metadata": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", - "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", + "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", + "optional": true, + "peer": true, "dependencies": { - "gaxios": "^6.0.0", + "gaxios": "^5.0.0", "json-bigint": "^1.0.0" }, "engines": { - "node": ">=14" + "node": ">=12" + } + }, + "node_modules/gcp-metadata/node_modules/gaxios": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", + "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", + "optional": true, + "peer": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "peer": true, + "engines": { + "node": ">=6.9.0" } }, "node_modules/get-caller-file": { @@ -14550,6 +16333,18 @@ "node": ">=14" } }, + "node_modules/google-auth-library/node_modules/gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "dependencies": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/googleapis": { "version": "129.0.0", "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-129.0.0.tgz", @@ -15676,14 +17471,6 @@ "url": "https://www.buymeacoffee.com/2tmRKi9" } }, - "node_modules/infobox-parser/node_modules/camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "engines": { - "node": ">=4" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -16483,6 +18270,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -16718,6 +18516,31 @@ "regenerator-runtime": "^0.13.3" } }, + "node_modules/jpeg-autorotate": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jpeg-autorotate/-/jpeg-autorotate-9.0.0.tgz", + "integrity": "sha512-bMzp1iIOpqF2dWiMwb3Mc9MfexYuiBmznNIeVtnedqFrfVql3Ueptg7Cefz6ZJuJais8sb+mBGQD/hw3Ud8eRA==", + "dependencies": { + "glob": "^7.2.0", + "jpeg-js": "^0.4.3", + "piexifjs": "^1.0.6", + "yargs-parser": "^20.2.9" + }, + "bin": { + "jpeg-autorotate": "src/cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jpeg-autorotate/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, "node_modules/jpeg-js": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", @@ -17341,6 +19164,11 @@ "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", "integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw=" }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, "node_modules/lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -18665,33 +20493,68 @@ "integrity": "sha512-yc0LhH6tItlvfLBugVUEtgawwFU2sIe+cSdmRJJCTMZ5GEJyLxNyC/NIOAOGk67Fa8GNpOttO3Xz/1bHpXFD/g==" }, "node_modules/mobx": { - "version": "5.15.7", - "resolved": "https://registry.npmjs.org/mobx/-/mobx-5.15.7.tgz", - "integrity": "sha512-wyM3FghTkhmC+hQjyPGGFdpehrcX1KOXsDuERhfK2YbJemkUhEB+6wzEN639T21onxlfYBmriA1PFnvxTUhcKw==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.12.0.tgz", + "integrity": "sha512-Mn6CN6meXEnMa0a5u6a5+RKrqRedHBhZGd15AWLk9O6uFY4KYHzImdt8JI8WODo1bjTSRnwXhJox+FCUZhCKCQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mobx" } }, "node_modules/mobx-react": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.4.4.tgz", - "integrity": "sha512-2mTzpyEjVB/RGk2i6KbcmP4HWcAUFox5ZRCrGvSyz49w20I4C4qql63grPpYrS9E9GKwgydBHQlA4y665LuRCQ==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-9.1.0.tgz", + "integrity": "sha512-DeDRTYw4AlgHw8xEXtiZdKKEnp+c5/jeUgTbTQXEqnAzfkrgYRWP3p3Nv3Whc2CEcM/mDycbDWGjxKokQdlffg==", + "dependencies": { + "mobx-react-lite": "^4.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/mobx-react-lite": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-4.0.5.tgz", + "integrity": "sha512-StfB2wxE8imKj1f6T8WWPf4lVMx3cYH9Iy60bbKXEs21+HQ4tvvfIBZfSmMXgQAefi8xYEwQIz4GN9s0d2h7dg==", "dependencies": { - "hoist-non-react-statics": "^3.0.0", - "react-lifecycles-compat": "^3.0.2" + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" }, "peerDependencies": { - "mobx": "^4.0.0 || ^5.0.0", - "react": "^0.13.0 || ^0.14.0 || ^15.0.0 || ^16.0.0" + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } } }, "node_modules/mobx-utils": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/mobx-utils/-/mobx-utils-5.6.2.tgz", - "integrity": "sha512-a/WlXyGkp6F12b01sTarENpxbmlRgPHFyR1Xv2bsSjQBm5dcOtd16ONb40/vOqck8L99NHpI+C9MXQ+SZ8f+yw==", + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/mobx-utils/-/mobx-utils-6.0.8.tgz", + "integrity": "sha512-fPNt0vJnHwbQx9MojJFEnJLfM3EMGTtpy4/qOOW6xueh1mPofMajrbYAUvByMYAvCJnpy1A5L0t+ZVB5niKO4g==", "peerDependencies": { - "mobx": "^4.13.1 || ^5.13.1" + "mobx": "^6.0.0" } }, "node_modules/mocha": { @@ -19609,12 +21472,6 @@ "node": ">=0.10.0" } }, - "node_modules/native-or-bluebird": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/native-or-bluebird/-/native-or-bluebird-1.2.0.tgz", - "integrity": "sha1-OcR7/Xgl0fuf+tMiEK4l2q3xAck=", - "deprecated": "'native-or-bluebird' is deprecated. Please use 'any-promise' instead." - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -19745,9 +21602,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/node-stream-zip": { "version": "1.15.0", @@ -22823,14 +24680,15 @@ } }, "node_modules/object.getownpropertydescriptors": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz", - "integrity": "sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.7.tgz", + "integrity": "sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g==", "dependencies": { - "array.prototype.reduce": "^1.0.5", + "array.prototype.reduce": "^1.0.6", "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "safe-array-concat": "^1.0.0" }, "engines": { "node": ">= 0.8" @@ -23553,6 +25411,11 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/piexifjs": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/piexifjs/-/piexifjs-1.0.6.tgz", + "integrity": "sha512-0wVyH0cKohzBQ5Gi2V1BuxYpxWfxF3cSqfFXfPIpl5tl9XLS5z4ogqhUCD20AbHi0h9aJkqXNJnkVev6gwh2ag==" + }, "node_modules/pipe-functions": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/pipe-functions/-/pipe-functions-1.3.0.tgz", @@ -23644,25 +25507,6 @@ "semver-compare": "^1.0.0" } }, - "node_modules/plist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/plist/-/plist-1.2.0.tgz", - "integrity": "sha512-dL9Xc2Aj3YyBnwvCNuHmFl2LWvQacm/HEAsoVwLiuu0POboMChETt5wexpU1P6F6MnibIucXlVsMFFgNUT2IyA==", - "dependencies": { - "base64-js": "0.0.8", - "util-deprecate": "1.0.2", - "xmlbuilder": "4.0.0", - "xmldom": "0.1.x" - } - }, - "node_modules/plist/node_modules/base64-js": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/pngjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", @@ -23805,9 +25649,9 @@ } }, "node_modules/prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", - "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -23899,6 +25743,13 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/prosemirror": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/prosemirror/-/prosemirror-0.11.1.tgz", + "integrity": "sha512-IZ35mmexuo3DNkMXs2A3bAm1jdlAJRVPor/bX1AWT+TdAR9fv6igUjRUFtQDCRUKwxH7ufwL1p6Um/MdgcbVIw==", + "deprecated": "This library has been split up into separate modules. This is the old monolithic package, which is no longer maintained. Use prosemirror-view, prosemirror-model, etc instead.", + "peer": true + }, "node_modules/prosemirror-commands": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz", @@ -24365,15 +26216,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-audio-waveform": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/react-audio-waveform/-/react-audio-waveform-0.0.5.tgz", - "integrity": "sha512-4dJwhl+LQRuywzmmjuhWT5GueT3Ai2ZhB+loVxg0sRdhplyDp96xAu10/V/+J25Cl7YqNtl2DWSxvSoI/i6l6w==", - "peerDependencies": { - "react": "^15.5.4", - "react-dom": "^15.4.1" - } - }, "node_modules/react-autosuggest": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/react-autosuggest/-/react-autosuggest-10.1.0.tgz", @@ -24675,17 +26517,6 @@ "react": ">= 16.3" } }, - "node_modules/react-reveal": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/react-reveal/-/react-reveal-1.2.2.tgz", - "integrity": "sha512-JCv3fAoU6Z+Lcd8U48bwzm4pMZ79qsedSXYwpwt6lJNtj/v5nKJYZZbw3yhaQPPgYePo3Y0NOCoYOq/jcsisuw==", - "dependencies": { - "prop-types": "^15.5.10" - }, - "peerDependencies": { - "react": "^15.3.0 || ^16.0.0" - } - }, "node_modules/react-select": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", @@ -24956,11 +26787,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -25024,6 +26879,41 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, "node_modules/rehype-raw": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", @@ -25629,18 +27519,6 @@ "node": ">=10.17.0" } }, - "node_modules/run-applescript/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/run-applescript/node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -28159,7 +30037,6 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -28174,9 +30051,9 @@ "integrity": "sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ==" }, "node_modules/typescript-language-server": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript-language-server/-/typescript-language-server-4.1.3.tgz", - "integrity": "sha512-miJcwsS5ZGuYlix9mbGZDF96ynzgxAZbCeQO2MpgaVahmnRjoZ3dI6hnnsvBbdTrpHAAEqdigOnVezoOzcXSag==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/typescript-language-server/-/typescript-language-server-4.2.0.tgz", + "integrity": "sha512-1yKDqKeWLTQkN4mN+CT84aBr7ckp6sNVb8DZg+eXl0TDl14edn6Yh1wPqPA1rQ4AGVJc02fYbXTFsklaVYy4Uw==", "bin": { "typescript-language-server": "lib/cli.mjs" }, @@ -28229,6 +30106,42 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, "node_modules/unicode-trie": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-0.3.1.tgz", @@ -28453,9 +30366,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "funding": [ { "type": "opencollective", @@ -28608,6 +30521,14 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/utif2": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz", @@ -29454,9 +31375,9 @@ } }, "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" }, "node_modules/which-typed-array": { "version": "1.1.13", @@ -29785,37 +31706,12 @@ "node": ">=4.0" } }, - "node_modules/xmlbuilder": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.0.0.tgz", - "integrity": "sha1-mLj2UcowqmJANvEn0RzGbce5B6M=", - "dependencies": { - "lodash": "^3.5.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/xmlbuilder/node_modules/lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==" - }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, - "node_modules/xmldom": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", - "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==", - "deprecated": "Deprecated due to CVE-2021-21366 resolved in 0.5.0", - "engines": { - "node": ">=0.1" - } - }, "node_modules/xmlhttprequest-ssl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", @@ -29881,12 +31777,11 @@ } }, "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha512-WhzC+xgstid9MbVUktco/bf+KJG+Uu6vMX0LN1sLJvwmbCQVxb4D8LzogobonKycNasCZLdOzTAk1SK7+K7swg==", "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "camelcase": "^4.1.0" } }, "node_modules/yargs-unparser": { @@ -29910,6 +31805,14 @@ "node": ">=6" } }, + "node_modules/yargs/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, "node_modules/yargs/node_modules/string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -29934,6 +31837,15 @@ "node": ">=6" } }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 151e45124..42b3c1ce2 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,8 @@ }, "dependencies": { "@azure/storage-blob": "^12.17.0", + "@babel/preset-env": "^7.23.5", + "@babel/preset-react": "^7.23.3", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@ffmpeg/core": "0.12.4", @@ -127,6 +129,7 @@ "async": "^3.2.5", "axios": "^1.6.2", "babel": "^6.23.0", + "babel-loader": "^9.1.3", "bcrypt-nodejs": "0.0.3", "bezier-curve": "^1.0.0", "bezier-js": "^6.1.4", @@ -141,7 +144,6 @@ "canvas": "^2.11.2", "chart.js": "^4.4.0", "child_process": "^1.0.2", - "chrome": "^0.1.0", "class-transformer": "^0.5.1", "color": "^4.2.3", "colors": "^1.4.0", @@ -191,6 +193,7 @@ "image-size": "^1.0.2", "image-size-stream": "^1.1.0", "jimp": "^0.22.10", + "jpeg-autorotate": "^9.0.0", "jquery": "^3.7.1", "js-datepicker": "^5.18.2", "jsonschema": "^1.4.1", @@ -200,9 +203,9 @@ "md5-file": "^5.0.0", "memorystream": "^0.3.1", "mobile-detect": "^1.4.5", - "mobx": "^5.15.7", - "mobx-react": "^5.4.4", - "mobx-utils": "^5.6.2", + "mobx": "^6.12.0", + "mobx-react": "^9.1.0", + "mobx-utils": "^6.0.8", "mongodb": "^6.3.0", "mongoose": "^8.0.2", "node-stream-zip": "^1.15.0", @@ -237,7 +240,6 @@ "raw-loader": "^4.0.2", "rc-switch": "^4.1.0", "react": "^18.2.0", - "react-audio-waveform": "0.0.5", "react-autosuggest": "^10.1.0", "react-color": "^2.19.3", "react-compound-slider": "^3.4.0", @@ -250,7 +252,6 @@ "react-markdown": "^9.0.1", "react-measure": "^2.5.2", "react-resizable": "^3.0.5", - "react-reveal": "^1.2.2", "react-select": "^5.8.0", "readline": "^1.3.0", "recharts": "^2.10.3", diff --git a/src/.babelrc b/src/.babelrc new file mode 100644 index 000000000..86ef21087 --- /dev/null +++ b/src/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env", "@babel/preset-react"] +} diff --git a/src/Utils.ts b/src/Utils.ts index 26514622c..d54760100 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -7,6 +7,7 @@ import { DocumentType } from './client/documents/DocumentTypes'; import { Colors } from './client/views/global/globalEnums'; import { Message } from './server/Message'; import * as Color from 'color'; +import { action, makeObservable } from 'mobx'; export namespace Utils { export let CLICK_TIME = 300; @@ -439,6 +440,12 @@ export namespace Utils { socket.on(message, (room: any) => handler(socket, room)); } } +export function copyProps(thing: { _prevProps: any; props: any; _props: any }) { + Object.keys(thing._prevProps).forEach(action(pkey => + (thing._prevProps as any)[pkey] !== (thing.props as any)[pkey] && + ((thing._props as any)[pkey] = (thing.props as any)[pkey]))); // prettier-ignore + thing._prevProps = thing.props; +} export function OmitKeys(obj: any, keys: string[], pattern?: string, addKeyFunc?: (dup: any) => void): { omit: any; extract: any } { const omit: any = { ...obj }; diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index df92fe50e..6217cf04b 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -57,7 +57,7 @@ export namespace DocServer { Doc.AddDocToList(Doc.MyRecentlyClosed, undefined, link); } }); - LinkManager.userLinkDBs.forEach(linkDb => Doc.FindReferences(linkDb, references, undefined)); + LinkManager.Instance.userLinkDBs.forEach(linkDb => Doc.FindReferences(linkDb, references, undefined)); const filtered = Array.from(references); const newCacheUpdate = filtered.map(doc => doc[Id]).join(';'); diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 87010f770..427b11751 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -32,7 +32,6 @@ export enum DocumentType { IMPORT = 'import', PRES = 'presentation', PRESELEMENT = 'preselement', - COLOR = 'color', YOUTUBE = 'youtube', COMPARISON = 'comparison', GROUP = 'group', diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4ec100728..37196187b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -32,7 +32,6 @@ import { ContextMenu } from '../views/ContextMenu'; import { ContextMenuProps } from '../views/ContextMenuItem'; import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke'; import { AudioBox, media_state } from '../views/nodes/AudioBox'; -import { ColorBox } from '../views/nodes/ColorBox'; import { ComparisonBox } from '../views/nodes/ComparisonBox'; import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox'; import { EquationBox } from '../views/nodes/EquationBox'; @@ -495,13 +494,6 @@ export namespace Docs { options: { _width: 400 }, }, ], - [ - DocumentType.COLOR, - { - layout: { view: ColorBox, dataField: defaultDataKey }, - options: { _nativeWidth: 220, _nativeHeight: 300 }, - }, - ], [ DocumentType.IMG, { @@ -1018,9 +1010,6 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.SEARCH), new List([]), options); } - export function ColorDocument(options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.COLOR), '', options); - } export function LoadingDocument(file: File | string, options: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.LOADING), undefined, { _height: 150, _width: 200, title: typeof file == 'string' ? file : file.name, ...options }, undefined, ''); } @@ -1638,7 +1627,7 @@ export namespace DocUtils { options = { ...options, _width: 400, _height: 512, title: path }; } - return ctor ? ctor(path, options, overwriteDoc) : undefined; + return ctor ? ctor(path, overwriteDoc ? { ...options, title: StrCast(overwriteDoc.title, path) } : options, overwriteDoc) : undefined; } export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false, pivotField?: string, pivotValue?: string): void { diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index ad5a1654d..7f82ff70a 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,4 +1,4 @@ -import { action, computed, observable, ObservableSet, observe } from 'mobx'; +import { action, computed, makeObservable, observable, ObservableSet, observe } from 'mobx'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { AclAdmin, AclEdit, Animation } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; @@ -22,8 +22,8 @@ const { Howl } = require('howler'); export class DocumentManager { //global holds all of the nodes (regardless of which collection they're in) @observable _documentViews = new Set(); - @observable public LinkAnchorBoxViews: DocumentView[] = []; - @observable public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = []; + @observable public LinkAnchorBoxViews: DocumentView[] = observable([]); + @observable public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = observable([]); @computed public get DocumentViews() { return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(view.docViewPath))); } @@ -38,11 +38,12 @@ export class DocumentManager { public static get Instance(): DocumentManager { return this._instance || (this._instance = new this()); } + @observable public CurrentlyLoading: Doc[] = observable([]); // this assignment doesn't work. the actual assignment happens in DocumentManager's constructor //private constructor so no other class can create a nodemanager private constructor() { - if (!LoadingBox.CurrentlyLoading) LoadingBox.CurrentlyLoading = []; - observe(LoadingBox.CurrentlyLoading, change => { + makeObservable(this); + observe(this.CurrentlyLoading, change => { // watch CurrentlyLoading-- when something is loaded, it's removed from the list and we have to update its icon if it were iconified since LoadingBox icons are different than the media they become switch (change.type as any) { case 'update': diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 30e448797..55aac5eb0 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -21,7 +21,6 @@ import { DocumentManager } from '../DocumentManager'; import './DirectoryImportBox.scss'; import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from './ImportMetadataEntry'; import * as React from 'react'; -import * as _ from 'lodash'; const unsupported = ['text/html', 'text/plain']; @@ -157,7 +156,7 @@ export class DirectoryImportBox extends React.Component { x: NumCast(doc.x), y: NumCast(doc.y) + offset, }; - const parent = this.props.DocumentView?.().props.docViewPath().lastElement(); + const parent = this.props.DocumentView?.()._props.docViewPath().lastElement(); if (parent?.Document.type === DocumentType.COL) { let importContainer: Doc; if (docs.length < 50) { diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 3e98ea379..8346949ba 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -1,4 +1,4 @@ -import { action, observable, observe, runInAction } from 'mobx'; +import { action, makeObservable, observable, observe, runInAction } from 'mobx'; import { computedFn } from 'mobx-utils'; import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc'; import { DirectLinks } from '../../fields/DocSymbols'; @@ -22,7 +22,7 @@ import { ScriptingGlobals } from './ScriptingGlobals'; */ export class LinkManager { @observable static _instance: LinkManager; - @observable static userLinkDBs: Doc[] = []; + @observable userLinkDBs: Doc[] = observable([]); @observable public static currentLink: Opt; @observable public static currentLinkAnchor: Opt; public static get Instance() { @@ -32,21 +32,21 @@ export class LinkManager { public static Links(doc: Doc | undefined) { return doc ? LinkManager.Instance.getAllRelatedLinks(doc) : []; } - public static addLinkDB = async (linkDb: any) => { + public addLinkDB = async (linkDb: any) => { await Promise.all( ((await DocListCastAsync(linkDb.data)) ?? []).map(link => // makes sure link anchors are loaded to avoid incremental updates to computedFns in LinkManager [PromiseValue(link?.link_anchor_1), PromiseValue(link?.link_anchor_2)] ) ); - LinkManager.userLinkDBs.push(linkDb); + this.userLinkDBs.push(linkDb); }; public static AutoKeywords = 'keywords:Usages'; static _links: Doc[] = []; constructor() { + makeObservable(this); LinkManager._instance = this; this.createlink_relationshipLists(); - LinkManager.userLinkDBs = []; // since this is an action, not a reaction, we get only one shot to add this link to the Anchor docs // Thus make sure all promised values are resolved from link -> link.proto -> link.link_anchor_[1,2] -> link.link_anchor_[1,2].proto // Then add the link to the anchor protos. @@ -124,7 +124,7 @@ export class LinkManager { } }; observe( - LinkManager.userLinkDBs, + this.userLinkDBs, change => { switch (change.type as any) { case 'splice': @@ -136,7 +136,7 @@ export class LinkManager { true ); runInAction(() => (FieldLoader.ServerLoadStatus.message = 'links')); - LinkManager.addLinkDB(Doc.LinkDBDoc()); + this.addLinkDB(Doc.LinkDBDoc()); } public createlink_relationshipLists = () => { diff --git a/src/client/util/RTFMarkup.tsx b/src/client/util/RTFMarkup.tsx index c8940194c..495af6abd 100644 --- a/src/client/util/RTFMarkup.tsx +++ b/src/client/util/RTFMarkup.tsx @@ -26,7 +26,7 @@ export class RTFMarkup extends React.Component<{}> { RTFMarkup.Instance = this; } - @observable _stats: { [key: string]: any } | undefined; + @observable _stats: { [key: string]: any } | undefined = undefined; /** * @returns the main interface of the SharingManager. diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 25f158f40..d36a360a1 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -1,4 +1,4 @@ -import { action, observable } from 'mobx'; +import { action, makeObservable, observable } from 'mobx'; import { Doc, Opt } from '../../fields/Doc'; import { DocViews } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; @@ -12,9 +12,13 @@ import { UndoManager } from './UndoManager'; export namespace SelectionManager { class Manager { - @observable SelectedViews: DocumentView[] = []; + @observable SelectedViews: DocumentView[] = observable([]); @observable IsDragging: boolean = false; - @observable SelectedSchemaDocument: Doc | undefined; + @observable SelectedSchemaDocument: Doc | undefined = undefined; + + constructor() { + makeObservable(this); + } @action SelectSchemaViewDoc(doc: Opt) { @@ -26,7 +30,7 @@ export namespace SelectionManager { if (!extendSelection) this.DeselectAll(); manager.SelectedViews.push(docView); docView.SELECTED = true; - docView.props.whenChildContentsActiveChanged(true); + docView._props.whenChildContentsActiveChanged(true); } } @action @@ -34,7 +38,7 @@ export namespace SelectionManager { if (docView && manager.SelectedViews.includes(docView)) { docView.SELECTED = false; manager.SelectedViews.splice(manager.SelectedViews.indexOf(docView), 1); - docView.props.whenChildContentsActiveChanged(false); + docView._props.whenChildContentsActiveChanged(false); } } @action @@ -44,7 +48,7 @@ export namespace SelectionManager { manager.SelectedSchemaDocument = undefined; manager.SelectedViews.forEach(dv => { dv.SELECTED = false; - dv.props.whenChildContentsActiveChanged(false); + dv._props.whenChildContentsActiveChanged(false); }); manager.SelectedViews.length = 0; } @@ -87,7 +91,7 @@ export namespace SelectionManager { ScriptingGlobals.add(function SelectionManager_selectedDocType(type: string, expertMode: boolean, checkContext?: boolean) { if (Doc.noviceMode && expertMode) return false; if (type === 'tab') { - return SelectionManager.Views().lastElement()?.props.renderDepth === 0; + return SelectionManager.Views().lastElement()?._props.renderDepth === 0; } let selected = (sel => (checkContext ? DocCast(sel?.embedContainer) : sel))(SelectionManager.SelectedSchemaDoc() ?? SelectionManager.Docs().lastElement()); return selected?.type === type || selected?.type_collection === type || !type; @@ -115,7 +119,7 @@ ScriptingGlobals.add(function redo() { }); ScriptingGlobals.add(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) { const docs = SelectionManager.Views() - .map(dv => dv.props.Document) + .map(dv => dv.Document) .filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.KVP && (!excludeCollections || d.type !== DocumentType.COL || !Cast(d.data, listSpec(Doc), null))); return docs.length ? new List(docs) : prevValue; }); diff --git a/src/client/util/ServerStats.tsx b/src/client/util/ServerStats.tsx index 08dbaac5d..7d5e0458d 100644 --- a/src/client/util/ServerStats.tsx +++ b/src/client/util/ServerStats.tsx @@ -36,7 +36,7 @@ export class ServerStats extends React.Component<{}> { ServerStats.Instance = this; } - @observable _stats: { [key: string]: any } | undefined; + @observable _stats: { [key: string]: any } | undefined = undefined; /** * @returns the main interface of the SharingManager. @@ -56,9 +56,7 @@ export class ServerStats extends React.Component<{}> {
Active users:{this._stats?.socketMap.length} - {this._stats?.socketMap.map((user: any) => ( -

{user.username}

- ))} + {this._stats?.socketMap.map((user: any) =>

{user.username}

)}
); diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 39c471970..ccf6fb820 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, ColorPicker, Dropdown, DropdownType, EditableText, Group, NumberDropdown, Size, Toggle, ToggleType, Type } from 'browndash-components'; -import { action, computed, observable, runInAction } from 'mobx'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { BsGoogle } from 'react-icons/bs'; @@ -45,11 +45,12 @@ export class SettingsManager extends React.Component<{}> { @observable private new_confirm = ''; @observable activeTab = 'Accounts'; - @observable public static propertiesWidth: number = 0; - @observable public static headerBarHeight: number = 0; + @observable public propertiesWidth: number = 0; + @observable public headerBarHeight: number = 0; constructor(props: {}) { super(props); + makeObservable(this); SettingsManager.Instance = this; this.matchSystem(); window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { @@ -116,7 +117,6 @@ export class SettingsManager extends React.Component<{}> { }); @undoBatch - @action changeColorScheme = action((scheme: string) => { Doc.UserDoc().userTheme = scheme; switch (scheme) { diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 403f4e090..a46c6363e 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -67,8 +67,8 @@ export class SharingManager extends React.Component<{}> { public static Instance: SharingManager; @observable private isOpen = false; // whether the SharingManager modal is open or not @observable public users: ValidatedUser[] = []; // the list of users with sharing docs - @observable private targetDoc: Doc | undefined; // the document being shared - @observable private targetDocView: DocumentView | undefined; // the DocumentView of the document being shared + @observable private targetDoc: Doc | undefined = undefined; // the document being shared + @observable private targetDocView: DocumentView | undefined = undefined; // the DocumentView of the document being shared // @observable private copied = false; @observable private dialogueBoxOpacity = 1; // for the modal @observable private overlayOpacity = 0.4; // for the modal diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts index fce43eef6..715eb021f 100644 --- a/src/client/util/SnappingManager.ts +++ b/src/client/util/SnappingManager.ts @@ -6,7 +6,7 @@ export namespace SnappingManager { @observable ShiftKey = false; @observable CtrlKey = false; @observable IsDragging: boolean = false; - @observable IsResizing: Doc | undefined; + @observable IsResizing: Doc | undefined = undefined; @observable CanEmbed: boolean = false; @observable public horizSnapLines: number[] = []; @observable public vertSnapLines: number[] = []; diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx index 412b8ba6e..f89624941 100644 --- a/src/client/views/AntimodeMenu.tsx +++ b/src/client/views/AntimodeMenu.tsx @@ -1,9 +1,8 @@ +import { action, makeObservable, observable, runInAction } from 'mobx'; import * as React from 'react'; -import { observable, action, runInAction } from 'mobx'; -import './AntimodeMenu.scss'; -import { StrCast } from '../../fields/Types'; -import { Doc } from '../../fields/Doc'; import { SettingsManager } from '../util/SettingsManager'; +import { copyProps } from '../../Utils'; +import './AntimodeMenu.scss'; export interface AntimodeMenuProps {} /** @@ -16,6 +15,18 @@ export abstract class AntimodeMenu extends React.Co protected _mainCont: React.RefObject = React.createRef(); protected _dragging: boolean = false; + _prevProps: React.PropsWithChildren; + @observable _props: React.PropsWithChildren; + constructor(props: React.PropsWithChildren) { + super(props); + this._props = this._prevProps = props; + makeObservable(this); + } + + componentDidUpdate() { + copyProps(this); + } + @observable protected _top: number = -300; @observable protected _left: number = -300; @observable protected _opacity: number = 0; diff --git a/src/client/views/AudioWaveform.scss b/src/client/views/AudioWaveform.scss deleted file mode 100644 index 6cbd1759a..000000000 --- a/src/client/views/AudioWaveform.scss +++ /dev/null @@ -1,17 +0,0 @@ -.audioWaveform { - position: relative; - width: 100%; - height: 200%; - overflow: hidden; - z-index: -1000; - bottom: 0; - pointer-events: none; - div { - height: 100% !important; - width: 100% !important; - } - canvas { - height: 100% !important; - width: 100% !important; - } -} diff --git a/src/client/views/AudioWaveform.tsx b/src/client/views/AudioWaveform.tsx deleted file mode 100644 index 1fd2fedc3..000000000 --- a/src/client/views/AudioWaveform.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import * as React from 'react'; -import axios from 'axios'; -import { action, computed, IReactionDisposer, reaction } from 'mobx'; -import { observer } from 'mobx-react'; -import Waveform from 'react-audio-waveform'; -import { Doc, NumListCast } from '../../fields/Doc'; -import { List } from '../../fields/List'; -import { listSpec } from '../../fields/Schema'; -import { Cast } from '../../fields/Types'; -import { numberRange } from '../../Utils'; -import './AudioWaveform.scss'; -import { Colors } from './global/globalEnums'; - -/** - * AudioWaveform - * - * Used in CollectionStackedTimeline to render a canvas with a visual of an audio waveform for AudioBox and VideoBox documents. - * Uses react-audio-waveform package. - * Bins the audio data into audioBuckets which are passed to package to render the lines. - * Calculates new buckets each time a new zoom factor or new set of trim bounds is created and stores it in a field on the layout doc with a title indicating the bounds and zoom for that list (see audioBucketField) - */ - -export interface AudioWaveformProps { - duration: number; // length of media clip - rawDuration: number; // length of underlying media data - mediaPath: string; - layoutDoc: Doc; - clipStart: number; - clipEnd: number; - zoomFactor: number; - PanelHeight: number; - PanelWidth: number; - fieldKey: string; -} - -@observer -export class AudioWaveform extends React.Component { - public static NUMBER_OF_BUCKETS = 100; // number of buckets data is divided into to draw waveform lines - - _disposer: IReactionDisposer | undefined; - - @computed get waveHeight() { - return Math.max(50, this.props.PanelHeight); - } - - @computed get clipStart() { - return this.props.clipStart; - } - @computed get clipEnd() { - return this.props.clipEnd; - } - @computed get zoomFactor() { - return this.props.zoomFactor; - } - - @computed get audioBuckets() { - return NumListCast(this.props.layoutDoc[this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor)]); - } - audioBucketField = (start: number, end: number, zoomFactor: number) => this.props.fieldKey + '_audioBuckets/' + '/' + start.toFixed(2).replace('.', '_') + '/' + end.toFixed(2).replace('.', '_') + '/' + zoomFactor * 10; - - componentWillUnmount() { - this._disposer?.(); - } - - componentDidMount() { - this._disposer = reaction( - () => ({ clipStart: this.clipStart, clipEnd: this.clipEnd, fieldKey: this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor), zoomFactor: this.props.zoomFactor }), - ({ clipStart, clipEnd, fieldKey, zoomFactor }) => { - if (!this.props.layoutDoc[fieldKey]) { - // setting these values here serves as a "lock" to prevent multiple attempts to create the waveform at nerly the same time. - const waveform = Cast(this.props.layoutDoc[this.audioBucketField(0, this.props.rawDuration, 1)], listSpec('number')); - this.props.layoutDoc[fieldKey] = waveform && new List(waveform.slice((clipStart / this.props.rawDuration) * waveform.length, (clipEnd / this.props.rawDuration) * waveform.length)); - setTimeout(() => this.createWaveformBuckets(fieldKey, clipStart, clipEnd, zoomFactor)); - } - }, - { fireImmediately: true } - ); - } - - // decodes the audio file into peaks for generating the waveform - createWaveformBuckets = async (fieldKey: string, clipStart: number, clipEnd: number, zoomFactor: number) => { - axios({ url: this.props.mediaPath, responseType: 'arraybuffer' }).then(response => { - const context = new window.AudioContext(); - context.decodeAudioData( - response.data, - action(buffer => { - const rawDecodedAudioData = buffer.getChannelData(0); - const startInd = clipStart / this.props.rawDuration; - const endInd = clipEnd / this.props.rawDuration; - const decodedAudioData = rawDecodedAudioData.slice(Math.floor(startInd * rawDecodedAudioData.length), Math.floor(endInd * rawDecodedAudioData.length)); - const numBuckets = Math.floor(AudioWaveform.NUMBER_OF_BUCKETS * zoomFactor); - - const bucketDataSize = Math.floor(decodedAudioData.length / numBuckets); - const brange = Array.from(Array(bucketDataSize)); - const bucketList = numberRange(numBuckets).map((i: number) => brange.reduce((p, x, j) => Math.abs(Math.max(p, decodedAudioData[i * bucketDataSize + j])), 0) / 2); - this.props.layoutDoc[fieldKey] = new List(bucketList); - }) - ); - }); - }; - - render() { - return ( -
- -
- ); - } -} diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 57bc11385..249e2c3a3 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -1,40 +1,42 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, IReactionDisposer, observable } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; -import './ContextMenu.scss'; -import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from './ContextMenuItem'; -import { Utils } from '../../Utils'; +import * as React from 'react'; import { StrCast } from '../../fields/Types'; -import { Doc } from '../../fields/Doc'; import { SettingsManager } from '../util/SettingsManager'; +import './ContextMenu.scss'; +import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from './ContextMenuItem'; @observer export class ContextMenu extends React.Component { static Instance: ContextMenu; - @observable private _items: Array = []; - @observable private _pageX: number = 0; - @observable private _pageY: number = 0; - @observable private _display: boolean = false; - @observable private _searchString: string = ''; - @observable private _showSearch: boolean = false; + private _ignoreUp = false; + private _reactionDisposer?: IReactionDisposer; + private _defaultPrefix: string = ''; + private _defaultItem: ((name: string) => void) | undefined; + private _onDisplay?: () => void = undefined; + + @observable _items: ContextMenuProps[] = observable([]); + @observable _pageX: number = 0; + @observable _pageY: number = 0; + @observable _display: boolean = false; + @observable _searchString: string = ''; + @observable _showSearch: boolean = false; // afaik displaymenu can be called before all the items are added to the menu, so can't determine in displayMenu what the height of the menu will be - @observable private _yRelativeToTop: boolean = true; - @observable selectedIndex = -1; + @observable _yRelativeToTop: boolean = true; + @observable _selectedIndex = -1; - @observable private _width: number = 0; - @observable private _height: number = 0; + @observable _width: number = 0; + @observable _height: number = 0; - @observable private _mouseX: number = -1; - @observable private _mouseY: number = -1; - @observable private _shouldDisplay: boolean = false; - private _ignoreUp = false; - private _reactionDisposer?: IReactionDisposer; + @observable _mouseX: number = -1; + @observable _mouseY: number = -1; + @observable _shouldDisplay: boolean = false; - constructor(props: Readonly<{}>) { + constructor(props: any) { super(props); - + makeObservable(this); ContextMenu.Instance = this; } @@ -74,36 +76,27 @@ export class ContextMenu extends React.Component { this._reactionDisposer?.(); } - @action - componentDidMount = () => { + componentDidMount() { document.addEventListener('pointerdown', this.onPointerDown, true); document.addEventListener('pointerup', this.onPointerUp); - }; + } @action clearItems() { - this._items = []; + this._items.length = 0; this._defaultPrefix = ''; this._defaultItem = undefined; } - _defaultPrefix: string = ''; - _defaultItem: ((name: string) => void) | undefined; - - findByDescription = (target: string, toLowerCase = false) => { - return this._items.find(menuItem => { - let reference = menuItem.description; - toLowerCase && (reference = reference.toLowerCase()); - return reference === target; - }); - }; + findByDescription = (target: string, toLowerCase = false) => + this._items.find(menuItem => + (toLowerCase ? menuItem.description.toLowerCase() : menuItem.description) === target); // prettier-ignore @action addItem(item: ContextMenuProps) { - if (this._items.indexOf(item) === -1) { - this._items.push(item); - } + !this._items.includes(item) && this._items.push(item); } + @action moveAfter(item: ContextMenuProps, after?: ContextMenuProps) { const curInd = this._items.findIndex(i => i.description === item.description); @@ -111,6 +104,7 @@ export class ContextMenu extends React.Component { const afterInd = after && this.findByDescription(after.description) ? this._items.findIndex(i => i.description === after.description) : this._items.length; this._items.splice(afterInd, 0, item); } + @action setDefaultItem(prefix: string, item: (name: string) => void) { this._defaultPrefix = prefix; @@ -126,7 +120,6 @@ export class ContextMenu extends React.Component { return this._pageY + this._height > window.innerHeight - ContextMenu.buffer ? window.innerHeight - ContextMenu.buffer - this._height : Math.max(0, this._pageY); } - _onDisplay?: () => void = undefined; @action displayMenu = (x: number, y: number, initSearch = '', showSearch = false, onDisplay?: () => void) => { //maxX and maxY will change if the UI/font size changes, but will work for any amount @@ -201,7 +194,7 @@ export class ContextMenu extends React.Component {
{value.join(' -> ')}
) : ( - + ) ); } @@ -211,7 +204,8 @@ export class ContextMenu extends React.Component { } render() { - return !this._display ? null : ( + console.log('DISPLAY = ' + this._display); + return (
{ @@ -221,6 +215,7 @@ export class ContextMenu extends React.Component { } })} style={{ + display: this._display ? '' : 'none', left: this.pageX, ...(this._yRelativeToTop ? { top: this.pageY } : { bottom: this.pageY }), background: SettingsManager.userBackgroundColor, @@ -242,17 +237,17 @@ export class ContextMenu extends React.Component { @action onKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'ArrowDown') { - if (this.selectedIndex < this.flatItems.length - 1) { - this.selectedIndex++; + if (this._selectedIndex < this.flatItems.length - 1) { + this._selectedIndex++; } e.preventDefault(); } else if (e.key === 'ArrowUp') { - if (this.selectedIndex > 0) { - this.selectedIndex--; + if (this._selectedIndex > 0) { + this._selectedIndex--; } e.preventDefault(); } else if (e.key === 'Enter' || e.key === 'Tab') { - const item = this.flatItems[this.selectedIndex]; + const item = this.flatItems[this._selectedIndex]; if (item) { item.event({ x: this.pageX, y: this.pageY }); } else if (this._searchString.startsWith(this._defaultPrefix)) { @@ -268,12 +263,12 @@ export class ContextMenu extends React.Component { onChange = (e: React.ChangeEvent) => { this._searchString = e.target.value; if (!this._searchString) { - this.selectedIndex = -1; + this._selectedIndex = -1; } else { - if (this.selectedIndex === -1) { - this.selectedIndex = 0; + if (this._selectedIndex === -1) { + this._selectedIndex = 0; } else { - this.selectedIndex = Math.min(this.flatItems.length - 1, this.selectedIndex); + this._selectedIndex = Math.min(this.flatItems.length - 1, this._selectedIndex); } } }; diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 6d97d965e..59b223c14 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -1,12 +1,11 @@ import * as React from 'react'; -import { observable, action, runInAction } from 'mobx'; +import { observable, action, runInAction, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { UndoManager } from '../util/UndoManager'; -import { Doc } from '../../fields/Doc'; -import { StrCast } from '../../fields/Types'; import { SettingsManager } from '../util/SettingsManager'; +import { copyProps } from '../../Utils'; export interface OriginalMenuProps { description: string; @@ -32,9 +31,20 @@ export class ContextMenuItem extends React.Component = []; @observable private overItem = false; - @action + _prevProps: ContextMenuProps & { selected?: boolean }; + @observable _props: ContextMenuProps & { selected?: boolean }; + constructor(props: ContextMenuProps & { selected?: boolean }) { + super(props); + this._props = this._prevProps = props; + makeObservable(this); + } + + componentDidUpdate() { + copyProps(this); + } + componentDidMount() { - this._items.length = 0; + runInAction(() => this._items.length = 0); if ((this.props as SubmenuProps)?.subitems) { (this.props as SubmenuProps).subitems?.forEach(i => runInAction(() => this._items.push(i))); } diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index d104eb90c..2ce0c085a 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable } from 'mobx'; +import { action, computed, makeObservable, observable, runInAction, untracked } from 'mobx'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocData } from '../../fields/DocSymbols'; @@ -21,17 +21,26 @@ export interface DocComponentProps { } export function DocComponent

() { class Component extends React.Component> { + @observable _props!: React.PropsWithChildren

; + constructor(props: React.PropsWithChildren

) { + super(props); + this._props = props; + makeObservable(this); + } + componentDidUpdate() { + // untracked(() => (this._props = this.props)); + } //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document() { - return this.props.Document; + return this._props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info @computed get layoutDoc() { - return this.props.LayoutTemplateString ? this.props.Document : Doc.Layout(this.props.Document, this.props.LayoutTemplate?.()); + return this._props.LayoutTemplateString ? this.Document : Doc.Layout(this.Document, this._props.LayoutTemplate?.()); } // This is the data part of a document -- ie, the data that is constant across all views of the document @computed get dataDoc() { - return this.props.Document[DocData] as Doc; + return this._props.Document[DocData] as Doc; } } return Component; @@ -49,22 +58,28 @@ interface ViewBoxBaseProps { } export function ViewBoxBaseComponent

() { class Component extends React.Component> { + @observable _props: React.PropsWithChildren

; + constructor(props: React.PropsWithChildren

) { + super(props); + this._props = props; + makeObservable(this); + } //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then //@computed get Document(): T { return schemaCtor(this.props.Document); } - @computed get Document() { - return this.props.Document; + get Document() { + return this._props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info - @computed get layoutDoc() { - return Doc.Layout(this.props.Document); + get layoutDoc() { + return Doc.Layout(this.Document); } // This is the data part of a document -- ie, the data that is constant across all views of the document - @computed get dataDoc() { - return this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc ? this.props.TemplateDataDocument ?? this.props.Document[DocData] : this.props.Document[DocData]; + get dataDoc() { + return this.Document.isTemplateForField || this.Document.isTemplateDoc ? this._props.TemplateDataDocument ?? this.Document[DocData] : this.Document[DocData]; } // key where data is stored - @computed get fieldKey() { - return this.props.fieldKey; + get fieldKey() { + return this._props.fieldKey; } } return Component; @@ -85,24 +100,30 @@ export interface ViewBoxAnnotatableProps { } export function ViewBoxAnnotatableComponent

() { class Component extends React.Component> { + @observable _props: React.PropsWithChildren

; + constructor(props: React.PropsWithChildren

) { + super(props); + this._props = props; + makeObservable(this); + } @observable _annotationKeySuffix = () => 'annotations'; @observable _isAnyChildContentActive = false; //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document() { - return this.props.Document; + return this._props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info @computed get layoutDoc() { - return Doc.Layout(this.props.Document); + return Doc.Layout(this.Document); } // This is the data part of a document -- ie, the data that is constant across all views of the document @computed get dataDoc() { - return this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc ? this.props.TemplateDataDocument ?? this.props.Document[DocData] : this.props.Document[DocData]; + return this.Document.isTemplateForField || this.Document.isTemplateDoc ? this._props.TemplateDataDocument ?? this.Document[DocData] : this.Document[DocData]; } // key where data is stored @computed get fieldKey() { - return this.props.fieldKey; + return this._props.fieldKey; } isAnyChildContentActive = () => this._isAnyChildContentActive; @@ -136,7 +157,7 @@ export function ViewBoxAnnotatableComponent

() if (targetDataDoc.isGroup && DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]).length < 2) { (DocumentManager.Instance.getFirstDocumentView(targetDataDoc)?.ComponentView as CollectionFreeFormView)?.promoteCollection(); } else { - this.isAnyChildContentActive() && this.props.select(false); + this.isAnyChildContentActive() && this._props.select(false); } return true; } @@ -149,7 +170,7 @@ export function ViewBoxAnnotatableComponent

() // moving it into the target. @action.bound moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string): boolean => { - if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { + if (Doc.AreProtosEqual(this._props.Document, targetCollection)) { return true; } const first = doc instanceof Doc ? doc : doc[0]; @@ -161,7 +182,7 @@ export function ViewBoxAnnotatableComponent

() @action.bound addDocument = (doc: Doc | Doc[], annotationKey?: string): boolean => { const docs = doc instanceof Doc ? [doc] : doc; - if (this.props.filterAddDocument?.(docs) === false || docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document) && Doc.LayoutField(doc) === Doc.LayoutField(this.props.Document))) { + if (this._props.filterAddDocument?.(docs) === false || docs.find(doc => Doc.AreProtosEqual(doc, this.Document) && Doc.LayoutField(doc) === Doc.LayoutField(this.Document))) { return false; } const targetDataDoc = this.dataDoc; @@ -190,7 +211,7 @@ export function ViewBoxAnnotatableComponent

() return true; }; - whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive))); + whenChildContentsActiveChanged = action((isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive))); } return Component; } diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index a64722a0b..47ec0f1b4 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -1,7 +1,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { action, computed, observable, runInAction } from 'mobx'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../fields/Doc'; import { RichTextField } from '../../fields/RichTextField'; @@ -60,8 +60,11 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV public static hasPushedHack = false; public static hasPulledHack = false; + @observable _props: { views: () => (DocumentView | undefined)[] }; constructor(props: { views: () => (DocumentView | undefined)[] }) { super(props); + this._props = props; + makeObservable(this); runInAction(() => (DocumentButtonBar.Instance = this)); } @@ -111,12 +114,12 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV }); get view0() { - return this.props.views()?.[0]; + return this._props.views()?.[0]; } @computed get considerGoogleDocsPush() { - const targetDoc = this.view0?.props.Document; + const targetDoc = this.view0?.Document; const published = targetDoc && Doc.GetProto(targetDoc)[GoogleRef] !== undefined; const animation = this.isAnimatingPulse ? 'shadow-pulse 1s linear infinite' : 'none'; return !targetDoc ? null : ( @@ -143,7 +146,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @computed get considerGoogleDocsPull() { - const targetDoc = this.view0?.props.Document; + const targetDoc = this.view0?.Document; const dataDoc = targetDoc && Doc.GetProto(targetDoc); const animation = this.isAnimatingFetch ? 'spin 0.5s linear infinite' : 'none'; @@ -214,7 +217,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @observable subFollow = ''; @computed get followLinkButton() { - const targetDoc = this.view0?.props.Document; + const targetDoc = this.view0?.Document; const followBtn = (allDocs: boolean, click: (doc: Doc) => void, isSet: (doc?: Doc) => boolean, icon: IconProp) => { const tooltip = `Follow ${this.subPin}documents`; return !tooltip ? null : ( @@ -229,7 +232,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV onPointerEnter={action(e => (this.subPin = allDocs ? 'All ' : ''))} onPointerLeave={action(e => (this.subPin = ''))} onClick={e => { - this.props.views().forEach(dv => click(dv!.Document)); + this._props.views().forEach(dv => click(dv!.Document)); e.stopPropagation(); }} /> @@ -243,7 +246,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV

this.props.views().map(view => view?.docView?.toggleFollowLink(undefined, false)))}> + onClick={undoBatch(e => this._props.views().map(view => view?.docView?.toggleFollowLink(undefined, false)))}>
{followBtn( true, @@ -260,7 +263,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @observable subLink = ''; @computed get linkButton() { - const targetDoc = this.view0?.props.Document; + const targetDoc = this.view0?.Document; return !targetDoc || !this.view0 ? null : (
@@ -304,7 +307,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV onPointerLeave={action(e => (this.subEndLink = ''))} onClick={e => { this.view0 && - DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.view0.props.Document, true, this.view0, { + DocumentLinksButton.finishLinkClick(e.clientX, e.clientY, DocumentLinksButton.StartLink, this.view0.Document, true, this.view0, { pinDocLayout: pinLayout, pinData: !pinContent ? {} : { poslayoutview: true, dataannos: true, dataview: pinContent }, } as PinProps); @@ -331,7 +334,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @observable subPin = ''; @computed get pinButton() { - const targetDoc = this.view0?.props.Document; + const targetDoc = this.view0?.Document; const pinBtn = (pinLayoutView: boolean, pinContentView: boolean, icon: IconProp) => { const tooltip = `Pin Document and Save ${this.subPin} to trail`; return !tooltip ? null : ( @@ -353,7 +356,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV )} onPointerLeave={action(e => (this.subPin = ''))} onClick={e => { - const docs = this.props + const docs = this._props .views() .filter(v => v) .map(dv => dv!.Document); @@ -376,7 +379,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
{ - const docs = this.props + const docs = this._props .views() .filter(v => v) .map(dv => dv!.Document); @@ -396,7 +399,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @computed get shareButton() { - const targetDoc = this.view0?.props.Document; + const targetDoc = this.view0?.Document; return !targetDoc ? null : ( {'Open Sharing Manager'}
}>
SharingManager.Instance.open(this.view0, targetDoc)}> @@ -408,10 +411,10 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @computed get menuButton() { - const targetDoc = this.view0?.props.Document; + const targetDoc = this.view0?.Document; return !targetDoc ? null : ( {`Open Context Menu`}
}> -
+
setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => this.openContextMenu(e))}>
@@ -427,10 +430,10 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV anchorPoint={anchorPoints.LEFT_TOP} content={ dv) - .map(dv => dv!.props.Document)} + .map(dv => dv!.Document)} suggestWithFunction /> // tfs: @bcz This might need to be the data document? }> @@ -447,7 +450,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV _stopFunc: () => void = emptyFunction; @computed get recordButton() { - const targetDoc = this.view0?.props.Document; + const targetDoc = this.view0?.Document; return !targetDoc ? null : ( Press to record audio annotation
}>
(DocumentV style={{ backgroundColor: this._isRecording ? Colors.ERROR_RED : Colors.DARK_GRAY, color: Colors.WHITE }} onPointerDown={action((e: React.PointerEvent) => { this._isRecording = true; - this.props.views().map(view => view && DocumentViewInternal.recordAudioAnnotation(view.dataDoc, view.LayoutFieldKey, stopFunc => (this._stopFunc = stopFunc), emptyFunction)); + this._props.views().map(view => view && DocumentViewInternal.recordAudioAnnotation(view.dataDoc, view.LayoutFieldKey, stopFunc => (this._stopFunc = stopFunc), emptyFunction)); const b = UndoManager.StartBatch('Recording'); setupMoveUpEvents( this, @@ -482,8 +485,8 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV onEmbedButtonMoved = () => { if (this._dragRef.current) { const dragDocView = this.view0!; - const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]); - const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + const dragData = new DragManager.DocumentDragData([dragDocView.Document]); + const [left, top] = dragDocView._props.ScreenToLocalTransform().inverse().transformPoint(0, 0); dragData.defaultDropAction = 'embed'; dragData.canEmbed = true; DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { hideSource: false }); @@ -497,7 +500,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @computed get templateButton() { const view0 = this.view0; - const views = this.props.views(); + const views = this._props.views(); return !view0 ? null : ( Tap to Customize Layout. Drag an embedding
} open={this._tooltipOpen} onClose={action(() => (this._tooltipOpen = false))} placement="bottom">
!this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true))}> @@ -522,7 +525,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV ); } - openContextMenu = (e: React.MouseEvent) => { + openContextMenu = (e: PointerEvent) => { let child = SelectionManager.Views()[0].ContentDiv!.children[0]; while (child.children.length) { const next = Array.from(child.children).find(c => c.className?.toString().includes('SVGAnimatedString') || typeof c.className === 'string'); @@ -559,7 +562,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @action toggleTrail = (e: React.PointerEvent) => { - const rootView = this.props.views()[0]; + const rootView = this._props.views()[0]; const doc = rootView?.Document; if (doc) { const anchor = rootView.ComponentView?.getAnchor?.(true) ?? doc; @@ -569,12 +572,12 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV anchor.presentationTrail = trail; } Doc.ActivePresentation = trail; - this.props.views().lastElement()?.props.addDocTab(trail, OpenWhere.replaceRight); + this._props.views().lastElement()?._props.addDocTab(trail, OpenWhere.replaceRight); } e.stopPropagation(); }; render() { - const doc = this.view0?.props.Document; + const doc = this.view0?.Document; if (!doc || !this.view0) return null; const isText = () => doc[this.view0!.LayoutFieldKey] instanceof RichTextField; @@ -589,9 +592,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
(link.link_displayLine = !IsFollowLinkScript(this.props.views().lastElement()?.Document.onClick))} - linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)} - linkFrom={() => this.props.views().lastElement()?.Document} + linkCreated={link => (link.link_displayLine = !IsFollowLinkScript(this._props.views().lastElement()?.Document.onClick))} + linkCreateAnchor={() => this._props.views().lastElement()?.ComponentView?.getAnchor?.(true)} + linkFrom={() => this._props.views().lastElement()?.Document} />
) : ( diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index b4c19df2d..6ef3fcc66 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { IconButton } from 'browndash-components'; -import { action, computed, observable, runInAction } from 'mobx'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { FaUndo } from 'react-icons/fa'; import { DateField } from '../../fields/DateField'; @@ -34,10 +34,15 @@ import { DocumentView, OpenWhereMod } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { ImageBox } from './nodes/ImageBox'; import * as React from 'react'; -import * as _ from 'lodash'; +interface DocumentDecorationsProps { + PanelWidth: number; + PanelHeight: number; + boundsLeft: number; + boundsTop: number; +} @observer -export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> { +export class DocumentDecorations extends React.Component { static Instance: DocumentDecorations; private _resizeHdlId = ''; private _keyinput = React.createRef(); @@ -61,8 +66,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P @observable private _showRotCenter = false; // whether to show a draggable green dot that represents the center of rotation @observable private _rotCenter = [0, 0]; // the center of rotation in object coordinates (0,0) = object center (not top left!) - constructor(props: any) { + @observable _props: React.PropsWithChildren; + constructor(props: React.PropsWithChildren) { super(props); + this._props = props; + makeObservable(this); DocumentDecorations.Instance = this; document.addEventListener('pointermove', // show decorations whenever pointer moves outside of selection bounds. action(e => { @@ -78,8 +86,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P @computed get ClippedBounds() { const bounds = this.Bounds; - const leftBounds = this.props.boundsLeft; - const topBounds = LightboxView.LightboxDoc ? 0 : this.props.boundsTop; + const leftBounds = this._props.boundsLeft; + const topBounds = LightboxView.LightboxDoc ? 0 : this._props.boundsTop; bounds.x = Math.max(leftBounds, bounds.x - this._resizeBorderWidth / 2) + this._resizeBorderWidth / 2; bounds.y = Math.max(topBounds, bounds.y - this._resizeBorderWidth / 2 - this._titleHeight) + this._resizeBorderWidth / 2 + this._titleHeight; const borderRadiusDraggerWidth = 15; @@ -92,7 +100,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P return (LinkFollower.IsFollowing || DocumentView.ExploreMode) ? { x: 0, y: 0, r: 0, b: 0 } : SelectionManager.Views() - .filter(dv => dv.props.renderDepth > 0) + .filter(dv => dv._props.renderDepth > 0) .map(dv => dv.getBounds()) .reduce((bounds, rect) => !rect ? bounds : { x: Math.min(rect.left, bounds.x), @@ -198,12 +206,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (containers.size > 1) return false; const { left, top } = dragDocView.getBounds() || { left: 0, top: 0 }; const dragData = new DragManager.DocumentDragData( - SelectionManager.Views().map(dv => dv.props.Document), - dragDocView.props.dropAction + SelectionManager.Views().map(dv => dv.Document), + dragDocView._props.dropAction ); - dragData.offset = dragDocView.props.ScreenToLocalTransform().transformDirection(e.x - left, e.y - top); - dragData.moveDocument = dragDocView.props.moveDocument; - dragData.removeDocument = dragDocView.props.removeDocument; + dragData.offset = dragDocView._props.ScreenToLocalTransform().transformDirection(e.x - left, e.y - top); + dragData.moveDocument = dragDocView._props.moveDocument; + dragData.removeDocument = dragDocView._props.removeDocument; dragData.isDocDecorationMove = true; dragData.canEmbed = dragTitle; this._hidden = true; @@ -223,7 +231,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P _deleteAfterIconify = false; _iconifyBatch: UndoManager.Batch | undefined; onCloseClick = (forceDeleteOrIconify: boolean | undefined) => { - const views = SelectionManager.Views().filter(v => v && v.props.renderDepth > 0); + const views = SelectionManager.Views().filter(v => v && v._props.renderDepth > 0); if (forceDeleteOrIconify === false && this._iconifyBatch) return; this._deleteAfterIconify = forceDeleteOrIconify || this._iconifyBatch ? true : false; var iconifyingCount = views.length; @@ -231,11 +239,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if ((force || --iconifyingCount === 0) && this._iconifyBatch) { if (this._deleteAfterIconify) { views.forEach(iconView => { - Doc.setNativeView(iconView.props.Document); - if (iconView.props.Document.activeFrame) { - iconView.props.Document.opacity = 0; // bcz: hacky ... allows inkMasks and other documents to be "turned off" without removing them from the animated collection which allows them to function properly in a presenation. + Doc.setNativeView(iconView.Document); + if (iconView.Document.activeFrame) { + iconView.Document.opacity = 0; // bcz: hacky ... allows inkMasks and other documents to be "turned off" without removing them from the animated collection which allows them to function properly in a presenation. } else { - iconView.props.removeDocument?.(iconView.props.Document); + iconView._props.removeDocument?.(iconView.Document); } }); views.forEach(SelectionManager.DeselectView); @@ -296,7 +304,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P SelectionManager.DeselectAll(); }; - onSelectContainerDocClick = () => SelectionManager.Views()?.[0]?.props.docViewPath?.().lastElement()?.select(false); + onSelectContainerDocClick = () => SelectionManager.Views()?.[0]?._props.docViewPath?.().lastElement()?.select(false); /** * sets up events when user clicks on the border radius editor */ @@ -344,7 +352,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P }; setRotateCenter = (seldocview: DocumentView, rotCenter: number[]) => { - const newloccentern = seldocview.props.ScreenToLocalTransform().transformPoint(rotCenter[0], rotCenter[1]); + const newloccentern = seldocview._props.ScreenToLocalTransform().transformPoint(rotCenter[0], rotCenter[1]); const newlocenter = [newloccentern[0] - NumCast(seldocview.layoutDoc._width) / 2, newloccentern[1] - NumCast(seldocview.layoutDoc._height) / 2]; const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.Document._rotation) / 180) * Math.PI); seldocview.Document.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width); @@ -376,7 +384,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const seldocview = SelectionManager.Views()[0]; SelectionManager.Views().forEach(dv => { const accumRot = (NumCast(dv.Document._rotation) / 180) * Math.PI; - const localRotCtr = dv.props.ScreenToLocalTransform().transformPoint(rcScreen.X, rcScreen.Y); + const localRotCtr = dv._props.ScreenToLocalTransform().transformPoint(rcScreen.X, rcScreen.Y); const localRotCtrOffset = [localRotCtr[0] - NumCast(dv.Document.width) / 2, localRotCtr[1] - NumCast(dv.Document.height) / 2]; const startRotCtr = Utils.rotPt(localRotCtrOffset[0], localRotCtrOffset[1], -accumRot); const unrotatedDocPos = { x: NumCast(dv.Document.x) + localRotCtrOffset[0] - startRotCtr.x, y: NumCast(dv.Document.y) + localRotCtrOffset[1] - startRotCtr.y }; @@ -454,7 +462,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P dot = (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]); return [a[0] + atob[0] * t, a[1] + atob[1] * t]; }; - const tl = docView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + const tl = docView._props.ScreenToLocalTransform().inverse().transformPoint(0, 0); return project([e.clientX + this._offset.x, e.clientY + this._offset.y], tl, [tl[0] + fixedAspect, tl[1] + 1]); }; onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => { @@ -475,7 +483,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P !this._interactionLock && runInAction(async () => { // resize selected docs if we're not in the middle of a resize (ie, throttle input events to frame rate) this._interactionLock = true; this._snapPt = thisPt; - e.ctrlKey && (SelectionManager.Views().forEach(docView => !Doc.NativeHeight(docView.props.Document) && docView.toggleNativeDimensions())); + e.ctrlKey && (SelectionManager.Views().forEach(docView => !Doc.NativeHeight(docView.Document) && docView.toggleNativeDimensions())); const fixedAspect = SelectionManager.Docs().some(this.hasFixedAspect); const scaleAspect = {x:scale.x === 1 && fixedAspect ? scale.y : scale.x, y: scale.x !== 1 && fixedAspect ? scale.x : scale.y}; SelectionManager.Views().forEach(docView => @@ -522,7 +530,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P doc.xPadding = NumCast(doc.xPadding) * scale.x; doc.yPadding = NumCast(doc.yPadding) * scale.y; } else { - const refCent = docView.props.ScreenToLocalTransform().transformPoint(refPt[0], refPt[1]); // fixed reference point for resize (ie, a point that doesn't move) + const refCent = docView._props.ScreenToLocalTransform().transformPoint(refPt[0], refPt[1]); // fixed reference point for resize (ie, a point that doesn't move) const [nwidth, nheight] = [docView.nativeWidth, docView.nativeHeight]; const [initWidth, initHeight] = [NumCast(doc._width, 1), NumCast(doc._height)]; @@ -615,7 +623,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ self: selected.Document, this: selected.layoutDoc }, console.log).result?.toString() || ''; } if (this._titleControlString.startsWith('#')) { - return Field.toString(selected.props.Document[this._titleControlString.substring(1)] as Field) || '-unset-'; + return Field.toString(selected.Document[this._titleControlString.substring(1)] as Field) || '-unset-'; } return this._accumulatedTitle; } @@ -625,7 +633,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P @computed get rotCenter() { const lastView = SelectionManager.Views().lastElement(); if (lastView) { - const invXf = lastView.props.ScreenToLocalTransform().inverse(); + const invXf = lastView._props.ScreenToLocalTransform().inverse(); const seldoc = lastView.layoutDoc; const loccenter = Utils.rotPt(NumCast(seldoc.rotation_centerX) * NumCast(seldoc._width), NumCast(seldoc.rotation_centerY) * NumCast(seldoc._height), invXf.Rotate); return invXf.transformPoint(loccenter.x + NumCast(seldoc._width) / 2, loccenter.y + NumCast(seldoc._height) / 2); @@ -648,16 +656,16 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P var shareSymbolIcon = ReverseHierarchyMap.get(shareMode)?.image; // hide the decorations if the parent chooses to hide it or if the document itself hides it - const hideDecorations = SnappingManager.GetIsResizing() || seldocview.props.hideDecorations || seldocview.Document.layout_hideDecorations; + const hideDecorations = SnappingManager.GetIsResizing() || seldocview._props.hideDecorations || seldocview.Document.layout_hideDecorations; const hideResizers = - ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveAcl(seldocview.Document)) || hideDecorations || seldocview.props.hideResizeHandles || seldocview.Document.layout_hideResizeHandles || this._isRounding || this._isRotating; - const hideTitle = this._showNothing || hideDecorations || seldocview.props.hideDecorationTitle || seldocview.Document.layout_hideDecorationTitle || this._isRounding || this._isRotating; - const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.Document.layout_hideDocumentButtonBar || this._isRounding || this._isRotating; + ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveAcl(seldocview.Document)) || hideDecorations || seldocview._props.hideResizeHandles || seldocview.Document.layout_hideResizeHandles || this._isRounding || this._isRotating; + const hideTitle = this._showNothing || hideDecorations || seldocview._props.hideDecorationTitle || seldocview.Document.layout_hideDecorationTitle || this._isRounding || this._isRotating; + const hideDocumentButtonBar = hideDecorations || seldocview._props.hideDocumentButtonBar || seldocview.Document.layout_hideDocumentButtonBar || this._isRounding || this._isRotating; // if multiple documents have been opened at the same time, then don't show open button const hideOpenButton = this._showNothing || hideDecorations || - seldocview.props.hideOpenButton || + seldocview._props.hideOpenButton || seldocview.Document.layout_hideOpenButton || SelectionManager.Views().some(docView => docView.Document._dragOnlyWithinContainer || docView.Document.isGroup || docView.Document.layout_hideOpenButton) || this._isRounding || @@ -667,10 +675,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P hideDecorations || this._isRounding || this._isRotating || - seldocview.props.hideDeleteButton || + seldocview._props.hideDeleteButton || seldocview.Document.hideDeleteButton || SelectionManager.Views().some(docView => { - const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().dataDoc) : AclEdit; + const collectionAcl = docView._props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView._props.docViewPath().lastElement().dataDoc) : AclEdit; return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.Document) !== AclAdmin; }); const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => ( @@ -798,7 +806,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
)} - {seldocview.props.renderDepth <= 1 || !seldocview.props.docViewPath().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')} + {seldocview._props.renderDepth <= 1 || !seldocview._props.docViewPath().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')} {useRounding && (
{ _editingDisposer?: IReactionDisposer; @observable _editing: boolean = false; + _prevProps: EditableProps; + @observable _props: EditableProps; constructor(props: EditableProps) { super(props); - this._editing = this.props.editing ? true : false; + this._props = this._prevProps = props; + makeObservable(this); + this._editing = this._props.editing ? true : false; } componentDidMount(): void { @@ -89,12 +96,12 @@ export class EditableView extends React.Component { ); } - @action componentDidUpdate() { - if (this._editing && this.props.editing === false) { + copyProps(this); + if (this._editing && this._props.editing === false) { this._inputref?.value && this.finalizeEdit(this._inputref.value, false, true, false); - } else if (this.props.editing !== undefined) { - this._editing = this.props.editing; + } else if (this._props.editing !== undefined) { + this._editing = this._props.editing; } } @@ -120,28 +127,28 @@ export class EditableView extends React.Component { case 'Tab': e.stopPropagation(); this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, false); - this.props.OnTab?.(e.shiftKey); + this._props.OnTab?.(e.shiftKey); break; case 'Backspace': e.stopPropagation(); - if (!e.currentTarget.value) this.props.OnEmpty?.(); + if (!e.currentTarget.value) this._props.OnEmpty?.(); break; case 'Enter': - if (this.props.allowCRs !== true) { + if (this._props.allowCRs !== true) { e.stopPropagation(); if (!e.ctrlKey) { this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true); - } else if (this.props.OnFillDown) { - this.props.OnFillDown(e.currentTarget.value); + } else if (this._props.OnFillDown) { + this._props.OnFillDown(e.currentTarget.value); this._editing = false; - this.props.isEditingCallback?.(false); + this._props.isEditingCallback?.(false); } } break; case 'Escape': e.stopPropagation(); this._editing = false; - this.props.isEditingCallback?.(false); + this._props.isEditingCallback?.(false); break; case 'ArrowUp': case 'ArrowDown': @@ -155,30 +162,30 @@ export class EditableView extends React.Component { case 'Control': break; case ':': - if (this.props.menuCallback) { + if (this._props.menuCallback) { e.stopPropagation(); - this.props.menuCallback(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y); + this._props.menuCallback(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y); break; } default: - if (this.props.textCallback?.(e.key)) { + if (this._props.textCallback?.(e.key)) { e.stopPropagation(); this._editing = false; - this.props.isEditingCallback?.(false); + this._props.isEditingCallback?.(false); } } }; @action onClick = (e: React.MouseEvent) => { - if (this.props.editing !== false) { + if (this._props.editing !== false) { e.nativeEvent.stopPropagation(); - if (this._ref.current && this.props.showMenuOnLoad) { - this.props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y); + if (this._ref.current && this._props.showMenuOnLoad) { + this._props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y); } else { this._editing = true; - this.props.isEditingCallback?.(true); + this._props.isEditingCallback?.(true); } // e.stopPropagation(); } @@ -186,17 +193,17 @@ export class EditableView extends React.Component { @action finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) { - if (this.props.SetValue(value, shiftDown, enterKey)) { + if (this._props.SetValue(value, shiftDown, enterKey)) { this._editing = false; - this.props.isEditingCallback?.(false); + this._props.isEditingCallback?.(false); } else { this._editing = false; - this.props.isEditingCallback?.(false); + this._props.isEditingCallback?.(false); !lostFocus && setTimeout( action(() => { this._editing = true; - this.props.isEditingCallback?.(true); + this._props.isEditingCallback?.(true); }), 0 ); @@ -215,9 +222,9 @@ export class EditableView extends React.Component { }; renderEditor() { - return this.props.autosuggestProps ? ( + return this._props.autosuggestProps ? ( { onClick: this.stopPropagation, onPointerUp: this.stopPropagation, onKeyPress: this.stopPropagation, - value: this.props.autosuggestProps.value, + value: this._props.autosuggestProps.value, // @ts-ignore - onChange: this.props.autosuggestProps.onChange, + onChange: this._props.autosuggestProps.onChange, }} /> - ) : this.props.oneLine !== false && this.props.GetValue()?.toString().indexOf('\n') === -1 ? ( + ) : this._props.oneLine !== false && this._props.GetValue()?.toString().indexOf('\n') === -1 ? ( (this._inputref = r)} - style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minWidth: 20, background: this.props.background }} - placeholder={this.props.placeholder} + style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minWidth: 20, background: this._props.background }} + placeholder={this._props.placeholder} onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)} - defaultValue={this.props.GetValue()} + defaultValue={this._props.GetValue()} autoFocus={true} onChange={this.onChange} onKeyDown={this.onKeyDown} @@ -253,10 +260,10 @@ export class EditableView extends React.Component {