From d182a3462a06ea58c4a0c937190aaa66eced0c01 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 24 Sep 2022 01:57:34 -0400 Subject: Fixed: treeView now doesn't get pointer events if it's not active. fixed layout of treeview for pres box. fixed horiz/vert scrolling for trees. fixed not adding Loading docs to recently closed. --- .../views/collections/CollectionTreeView.tsx | 73 ++++++++++++---------- 1 file changed, 41 insertions(+), 32 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index dce792d19..fe5dc17f5 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -83,7 +83,7 @@ export class CollectionTreeView extends CollectionSubView this._mainEle; @@ -111,7 +111,7 @@ export class CollectionTreeView extends CollectionSubView { if (!this._isDisposing) { const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace('px', '')); - const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()); + const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()) + 6; this.layoutDoc._autoHeightMargins = bodyHeight; this.props.setHeight?.(bodyHeight + titleHeight); } @@ -298,7 +298,11 @@ export class CollectionTreeView extends CollectionSubView (this._titleRef = r)}> +
(this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this.props.ScreenToLocalTransform().Scale))} + key={this.doc[Id]} + style={!this.outlineMode ? { paddingLeft: this.marginX(), paddingTop: this.marginTop() } : {}}> {this.outlineMode ? this.documentTitle : this.editableTitle}
); @@ -378,40 +382,45 @@ export class CollectionTreeView extends CollectionSubView (!this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined); const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar; return [ -
- {titleBar} +
+ {!this.buttonMenu && !this.noviceExplainer ? null : ( +
+ {this.buttonMenu} + {this.noviceExplainer} +
+ )}
- {!this.buttonMenu && !this.noviceExplainer ? null : ( -
r && (this._explainerHeight = r.getBoundingClientRect().height))}> - {this.buttonMenu} - {this.noviceExplainer} -
- )} + ...(!titleBar ? { paddingLeft: this.marginX(), paddingTop: this.marginTop() } : {}), + overflow: 'auto', + width: '100%', + height: '100%', + }}> + {titleBar}
e.stopPropagation()} - onDrop={this.onTreeDrop} - ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}> -
    {this.treeViewElements}
+ onContextMenu={this.onContextMenu}> +
e.stopPropagation()} + onDrop={this.onTreeDrop} + ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}> +
    {this.treeViewElements}
+
, -- cgit v1.2.3-70-g09d2 From ba73479fe6c0594ebe37eed6cf295e5adc49c8e1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 25 Oct 2022 11:10:12 -0400 Subject: various tweaks: show border highlights in tree views, uniform treatment of embedding using title bar, even for free form views, choose bestAlias when dragging from files menu, text boxes honor document moves, show title for timeline annotations, fix dragoffset for stacks with buttons/description headers, --- src/Utils.ts | 6 +- src/client/util/DocumentManager.ts | 4 +- src/client/util/DragManager.ts | 18 ++- src/client/views/DocumentDecorations.tsx | 7 +- src/client/views/StyleProvider.tsx | 17 ++- src/client/views/collections/CollectionSubView.tsx | 7 +- .../views/collections/CollectionTreeView.tsx | 7 +- src/client/views/collections/TreeView.tsx | 19 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 32 +++-- src/client/views/nodes/DocumentView.tsx | 136 ++++++++++----------- .../views/nodes/formattedText/FormattedTextBox.tsx | 3 + src/fields/Doc.ts | 5 + 12 files changed, 133 insertions(+), 128 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index bf1f72774..5e0514bc6 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -728,10 +728,10 @@ export function getWordAtPoint(elem: any, x: number, y: number): string | undefi return undefined; } -export function hasDescendantTarget(x: number, y: number, target: HTMLDivElement | null) { +export function isTargetChildOf(ele: HTMLDivElement | null, target: Element | null) { let entered = false; - for (let child = document.elementFromPoint(x, y); !entered && child; child = child.parentElement) { - entered = entered || child === target; + for (let child = target; !entered && child; child = child.parentElement) { + entered = child === ele; } return entered; } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 9a46d20de..b046d950f 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -335,9 +335,7 @@ export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) { } else { const context = doc.context !== Doc.MyFilesystem && Cast(doc.context, Doc, null); const showDoc = context || doc; - const bestAlias = showDoc === Doc.GetProto(showDoc) ? DocListCast(showDoc.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail) : showDoc; - - CollectionDockingView.AddSplit(bestAlias ? bestAlias : Doc.MakeAlias(showDoc), 'right') && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc, {})); + CollectionDockingView.AddSplit(Doc.BestAlias(showDoc), 'right') && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc, {})); } } ScriptingGlobals.add(DocFocusOrOpen); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 160aba294..899764866 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -206,7 +206,7 @@ export namespace DragManager { !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) : docDragData.dropAction === 'alias' - ? Doc.MakeAlias(d) + ? Doc.BestAlias(d) : docDragData.dropAction === 'proto' ? Doc.GetProto(d) : docDragData.dropAction === 'copy' @@ -260,10 +260,6 @@ export namespace DragManager { StartDrag([ele], dragData, downX, downY, options); } - export function StartImgDrag(ele: HTMLElement, downX: number, downY: number) { - StartDrag([ele], {}, downX, downY); - } - export function SetSnapLines(horizLines: number[], vertLines: number[]) { SnappingManager.setSnapLines(horizLines, vertLines); } @@ -325,7 +321,7 @@ export namespace DragManager { export let DocDragData: DocumentDragData | undefined; export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) { if (dragData.dropAction === 'none') return; - DocDragData = dragData instanceof DocumentDragData ? dragData : undefined; + DocDragData = dragData as DocumentDragData; const batch = UndoManager.StartBatch('dragging'); eles = eles.filter(e => e); CanEmbed = dragData.canEmbed || false; @@ -357,15 +353,15 @@ export namespace DragManager { let rot = 0; const docsToDrag = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnchorAnnoDragData ? [dragData.dragDocument] : []; const dragElements = eles.map(ele => { - let useDim = false; + // 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. \ + // 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; - const rotStr = ele.style.transform.replace(/.*rotate\(([-0-9.e]*)deg\).*/, '$1'); - if (rotStr) rot = Number(rotStr); + rot = Number(ele.style.transform.replace(/.*rotate\(([-0-9.e]*)deg\).*/, '$1') || 0); } else { useDim = true; } - if (rot < 0) rot += 360; if (!ele.parentNode) dragDiv.appendChild(ele); const dragElement = ele.parentNode === dragDiv ? ele : (ele.cloneNode(true) as HTMLElement); const children = Array.from(dragElement.children); @@ -387,7 +383,7 @@ export namespace DragManager { const rect = ele.getBoundingClientRect(); const w = ele.offsetWidth || rect.width; const h = ele.offsetHeight || rect.height; - const rotR = -(rot / 180) * Math.PI; + const rotR = -((rot < 0 ? rot + 360 : rot) / 180) * Math.PI; const tl = [0, 0]; const tr = [Math.cos(rotR) * w, Math.sin(-rotR) * w]; const bl = [Math.sin(rotR) * h, Math.cos(-rotR) * h]; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6cf7df357..10517d829 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -177,6 +177,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P ); 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 = this.Interacting = true; @@ -250,8 +251,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (selectedDocs.length) { if (e.ctrlKey) { // open an alias in a new tab with Ctrl Key - const bestAlias = DocListCast(selectedDocs[0].props.Document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail); - CollectionDockingView.AddSplit(bestAlias ?? Doc.MakeAlias(selectedDocs[0].props.Document), 'right'); + CollectionDockingView.AddSplit(Doc.BestAlias(selectedDocs[0].props.Document), 'right'); } else if (e.shiftKey) { // open centered in a new workspace with Shift Key const alias = Doc.MakeAlias(selectedDocs[0].props.Document); @@ -766,6 +766,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P onBlur={e => !hideTitle && this.titleBlur()} onChange={action(e => !hideTitle && (this._accumulatedTitle = e.target.value))} onKeyDown={hideTitle ? emptyFunction : this.titleEntered} + onPointerDown={e => e.stopPropagation()} /> ) : (
@@ -825,7 +826,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
{hideDeleteButton ?
: topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')} {hideResizers || hideDeleteButton ?
: topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')} - {hideResizers ?
: titleArea} + {titleArea} {hideOpenButton ?
: topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')}
{hideResizers ? null : ( diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index a5a886f42..2eb3dd532 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -3,8 +3,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, runInAction } from 'mobx'; import { extname } from 'path'; import { Doc, Opt } from '../../fields/Doc'; -import { BoolCast, Cast, ImageCast, NumCast, StrCast } from '../../fields/Types'; -import { DashColor, lightOrDark } from '../../Utils'; +import { BoolCast, Cast, DocCast, ImageCast, NumCast, StrCast } from '../../fields/Types'; +import { DashColor, emptyFunction, lightOrDark } from '../../Utils'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { DocFocusOrOpen } from '../util/DocumentManager'; import { ColorScheme } from '../util/SettingsManager'; @@ -42,6 +42,7 @@ export enum StyleProp { FontSize = 'fontSize', // size of text font FontFamily = 'fontFamily', // font family of text FontWeight = 'fontWeight', // font weight of text + Highlighting = 'highlighting', // border highlighting } function darkScheme() { @@ -107,6 +108,18 @@ export function DefaultStyleProvider(doc: Opt, props: Opt(moreProps?: X) { const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); if (movedDocs.length) { - const canAdd = - this.props.Document._viewType === CollectionViewType.Pile || - de.embedKey || - !this.props.isAnnotationOverlay || - this.props.Document.allowOverlayDrop || - Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document); + const canAdd = this.props.Document._viewType === CollectionViewType.Pile || de.embedKey || this.props.Document.allowOverlayDrop || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document); added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse); } else { ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData }); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index fe5dc17f5..1169f692a 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -147,6 +147,8 @@ export class CollectionTreeView extends CollectionSubView this.props.ScreenToLocalTransform().translate(0, -this._headerHeight); + @action remove = (doc: Doc | Doc[]): boolean => { const docs = doc instanceof Doc ? [doc] : doc; @@ -275,7 +277,7 @@ export class CollectionTreeView extends CollectionSubView boolean) => this.props.CollectionView?.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false; + @observable _headerHeight = 0; contentFunc = () => { const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor); const pointerEvents = () => (!this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined); @@ -384,7 +387,7 @@ export class CollectionTreeView extends CollectionSubView {!this.buttonMenu && !this.noviceExplainer ? null : ( -
+
r && (this._headerHeight = Number(getComputedStyle(r).height.replace(/px/, ''))))}> {this.buttonMenu} {this.noviceExplainer}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 409b615f4..b9f86fa6b 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -10,11 +10,12 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnOne, returnTrue, simulateMouseClick, Utils } from '../../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, simulateMouseClick, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; +import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; @@ -31,7 +32,6 @@ import { CollectionTreeView, TreeViewType } from './CollectionTreeView'; import { CollectionView } from './CollectionView'; import './TreeView.scss'; import React = require('react'); -import { ScriptingGlobals } from '../../util/ScriptingGlobals'; export interface TreeViewProps { treeView: CollectionTreeView; @@ -792,12 +792,14 @@ export class TreeView extends React.Component { titleStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (!doc || doc !== this.doc) return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView + // prettier-ignore switch (property.split(':')[0]) { - case StyleProp.Opacity: - return this.props.treeView.outlineMode ? undefined : 1; - case StyleProp.BackgroundColor: - return this.selected ? '#7089bb' : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); + case StyleProp.Opacity: return this.props.treeView.outlineMode ? undefined : 1; + case StyleProp.BackgroundColor: return this.selected ? '#7089bb' : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); + case StyleProp.Highlighting: if (this.props.treeView.outlineMode) return undefined; case StyleProp.DocContents: + const highlightIndex = this.props.treeView.outlineMode ? Doc.DocBrushStatus.unbrushed : Doc.isBrushedHighlightedDegree(doc); + const highlightColor = ['transparent', 'rgb(68, 118, 247)', 'rgb(68, 118, 247)', 'orange', 'lightBlue'][highlightIndex]; return this.props.treeView.outlineMode ? null : (
{ // just render a title for a tree view label (identified by treeViewDoc being set in 'props') maxWidth: props?.PanelWidth() || undefined, background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor), + outline: `solid ${highlightColor} ${highlightIndex}px`, }}> {StrCast(doc?.title)}
); - default: - return this.props?.treeView?.props.styleProvider?.(doc, props, property); } + return this.props?.treeView?.props.styleProvider?.(doc, props, property); }; embeddedStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (property.startsWith(StyleProp.Decorations)) return null; @@ -1011,6 +1013,7 @@ export class TreeView extends React.Component { pinToPres={this.props.treeView.props.pinToPres} disableDocBrushing={this.props.treeView.props.disableDocBrushing} bringToFront={returnFalse} + scriptContext={this} /> ); }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 88422cbd4..eca95e1e0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -113,7 +113,7 @@ export class CollectionFreeFormView extends CollectionSubView(); - @observable _marqueeRef = React.createRef(); + @observable _marqueeRef: HTMLDivElement | null = null; @observable _marqueeViewRef = React.createRef(); @observable ChildDrag: DocumentView | undefined; // child document view being dragged. needed to update drop areas of groups when a group item is dragged. @observable _brushedView = { width: 0, height: 0, panX: 0, panY: 0, opacity: 0 }; // highlighted region of freeform canvas used by presentations to indicate a region @@ -1011,22 +1011,22 @@ export class CollectionFreeFormView extends CollectionSubView { this._firstRender = false; - - this._marqueeRef.current?.addEventListener('dashDragAutoScroll', this.onDragAutoScroll as any); - this._disposers.groupBounds = reaction( () => { if (this.props.Document._isGroup && this.childDocs.length === this.childDocList?.length) { @@ -1668,7 +1665,7 @@ export class CollectionFreeFormView extends CollectionSubView disposer?.()); - this._marqueeRef.current?.removeEventListener('dashDragAutoScroll', this.onDragAutoScroll as any); + this._marqueeRef?.removeEventListener('dashDragAutoScroll', this.onDragAutoScroll as any); } @action @@ -1681,10 +1678,10 @@ export class CollectionFreeFormView extends CollectionSubView { - e.stopPropagation(); - }; - incrementalRender = action(() => { if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath())) { const unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])); @@ -1889,7 +1882,13 @@ export class CollectionFreeFormView extends CollectionSubView -
+
{ + this._marqueeRef = r; + r?.addEventListener('dashDragAutoScroll', this.onDragAutoScroll as any); + }} + style={{ opacity: this.props.dontRenderDocuments ? 0.7 : undefined }}> {this.layoutDoc._backgroundGridShow ? (
this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), 'add:right'), icon: 'layer-group' }); - !Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), 'add:right'), 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[DataSym]), icon: 'hand-point-right' }); - - let documentationDescription: string | undefined = undefined; - let documentationLink: string | undefined = undefined; - console.log("type: ", this.props.Document.type); - switch(this.props.Document.type) { - case DocumentType.COL: - documentationDescription = "See collection documentation"; - documentationLink = "https://brown-dash.github.io/Dash-Documentation/views/"; - break; - case DocumentType.PDF: - documentationDescription = "See PDF node documentation"; - documentationLink = "https://brown-dash.github.io/Dash-Documentation/documents/pdf/"; - break; - case DocumentType.VID: - documentationDescription = "See video node documentation"; - documentationLink = "https://brown-dash.github.io/Dash-Documentation/documents/tempMedia/video"; - break; - case DocumentType.AUDIO: - documentationDescription = "See audio node documentation"; - documentationLink = "https://brown-dash.github.io/Dash-Documentation/documents/tempMedia/audio"; - break; - case DocumentType.WEB: - documentationDescription = "See webpage node documentation"; - documentationLink = "https://brown-dash.github.io/Dash-Documentation/documents/webpage/"; - break; - case DocumentType.IMG: - documentationDescription = "See image node documentation"; - documentationLink = "https://brown-dash.github.io/Dash-Documentation/documents/images/"; - break; - case DocumentType.RTF: - documentationDescription = "See text node documentation"; - documentationLink = "https://brown-dash.github.io/Dash-Documentation/documents/text/"; - break; - default: - break; - } - - // Add link to help documentation - if (documentationDescription && documentationLink) { - console.log("add documentation item"); - helpItems.push({ description: documentationDescription, event: () => { + } + const help = cm.findByDescription('Help...'); + const helpItems: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : []; + helpItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), 'add:right'), icon: 'layer-group' }); + !Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), 'add:right'), 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[DataSym]), icon: 'hand-point-right' }); + + let documentationDescription: string | undefined = undefined; + let documentationLink: string | undefined = undefined; + switch (this.props.Document.type) { + case DocumentType.COL: + documentationDescription = 'See collection documentation'; + documentationLink = 'https://brown-dash.github.io/Dash-Documentation/views/'; + break; + case DocumentType.PDF: + documentationDescription = 'See PDF node documentation'; + documentationLink = 'https://brown-dash.github.io/Dash-Documentation/documents/pdf/'; + break; + case DocumentType.VID: + documentationDescription = 'See video node documentation'; + documentationLink = 'https://brown-dash.github.io/Dash-Documentation/documents/tempMedia/video'; + break; + case DocumentType.AUDIO: + documentationDescription = 'See audio node documentation'; + documentationLink = 'https://brown-dash.github.io/Dash-Documentation/documents/tempMedia/audio'; + break; + case DocumentType.WEB: + documentationDescription = 'See webpage node documentation'; + documentationLink = 'https://brown-dash.github.io/Dash-Documentation/documents/webpage/'; + break; + case DocumentType.IMG: + documentationDescription = 'See image node documentation'; + documentationLink = 'https://brown-dash.github.io/Dash-Documentation/documents/images/'; + break; + case DocumentType.RTF: + documentationDescription = 'See text node documentation'; + documentationLink = 'https://brown-dash.github.io/Dash-Documentation/documents/text/'; + break; + } + // Add link to help documentation + if (documentationDescription && documentationLink) { + console.log('add documentation item'); + helpItems.push({ + description: documentationDescription, + event: () => { window.open(documentationLink, '_blank'); - }, icon: 'book' }) - }; - - cm.addItem({ description: 'Help...', noexpand: true, subitems: helpItems, icon: 'question' }); + }, + icon: 'book', + }); } + cm.addItem({ description: 'Help...', noexpand: true, subitems: helpItems, icon: 'question' }); if (!this.topMost) e?.stopPropagation(); // DocumentViews should stop propagation of this event cm.displayMenu((e?.pageX || pageX || 0) - 15, (e?.pageY || pageY || 0) - 15); @@ -1411,29 +1409,23 @@ export class DocumentViewInternal extends DocComponent !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))} - onPointerLeave={action(e => !hasDescendantTarget(e.nativeEvent.x, e.nativeEvent.y, this.ContentDiv) && Doc.UnBrushDoc(this.props.Document))} + onPointerEnter={e => (!SnappingManager.GetIsDragging() || DragManager.CanEmbed) && Doc.BrushDoc(this.props.Document)} + onPointerOver={e => (!SnappingManager.GetIsDragging() || DragManager.CanEmbed) && Doc.BrushDoc(this.props.Document)} + onPointerLeave={e => !isParentOf(this.ContentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.props.Document)} style={{ display: this.hidden ? 'inline' : undefined, borderRadius: this.borderRounding, @@ -1453,9 +1446,6 @@ export class DocumentViewInternal extends DocComponent - {/*
- {animRenderDoc} -
*/} {animRenderDoc}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index a94e2c96d..f5d00c2b8 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -538,6 +538,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent !doc.context && doc.author === Doc.CurrentUserEmail) : doc; + return bestAlias ?? Doc.MakeAlias(doc); + } + export async function makeClone(doc: Doc, cloneMap: Map, linkMap: Map, rtfs: { copy: Doc; key: string; field: RichTextField }[], exclusions: string[], dontCreate: boolean, asBranch: boolean): Promise { if (Doc.IsBaseProto(doc)) return doc; if (cloneMap.get(doc[Id])) return cloneMap.get(doc[Id])!; -- cgit v1.2.3-70-g09d2 From 2fc88a931cb2fc3408297b000208990633445585 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 27 Oct 2022 15:57:09 -0400 Subject: cleaned up treeViews to work across PresBox/ppt slides/collections/ - modified DocumentView rendering to remove pres box refs. fixed mainView width. --- src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 8 +- src/client/views/DocumentDecorations.tsx | 18 +- src/client/views/LightboxView.tsx | 26 +-- src/client/views/MainView.tsx | 1 + src/client/views/StyleProvider.tsx | 5 +- .../views/collections/CollectionStackingView.tsx | 2 + .../views/collections/CollectionTreeView.scss | 2 - .../views/collections/CollectionTreeView.tsx | 62 ++++--- src/client/views/collections/CollectionView.tsx | 2 + src/client/views/collections/TabDocView.tsx | 1 - src/client/views/collections/TreeView.scss | 3 +- src/client/views/collections/TreeView.tsx | 179 +++++++++---------- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 37 ++-- src/client/views/nodes/FieldView.tsx | 2 - src/client/views/nodes/VideoBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 8 +- src/client/views/nodes/trails/PresBox.tsx | 7 +- src/client/views/nodes/trails/PresElementBox.scss | 14 +- src/client/views/nodes/trails/PresElementBox.tsx | 197 ++++++++++++--------- src/fields/Doc.ts | 3 + 23 files changed, 301 insertions(+), 290 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2d82ffdf9..bbb896d6e 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -335,7 +335,6 @@ export class DocumentOptions { treeViewHideHeaderIfTemplate?: boolean; // whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox) treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items. - treeViewGrowsHorizontally?: boolean; // whether an embedded tree view of the document can grow horizontally without growing vertically treeViewChildDoubleClick?: ScriptField; // // Action Button buttonMenu?: boolean; // whether a action button should be displayed @@ -395,7 +394,6 @@ export namespace Docs { _xMargin: 10, _yMargin: 10, nativeDimModifiable: true, - treeViewGrowsHorizontally: true, nativeHeightUnfrozen: true, forceReflow: true, links: '@links(self)', @@ -570,7 +568,7 @@ export namespace Docs { DocumentType.SLIDER, { layout: { view: SliderBox, dataField: defaultDataKey }, - options: { links: '@links(self)', treeViewGrowsHorizontally: true }, + options: { links: '@links(self)' }, }, ], [ diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 2bc464127..a2974177e 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -480,7 +480,7 @@ export class CurrentUserUtils { const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters const reqdOpts:DocumentOptions = { title: "My Dashboards", childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, boxShadow: "0 0", childDontRegisterViews: true, - targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, treeViewTruncateTitleWidth: 150, ignoreClick: true, + targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, treeViewTruncateTitleWidth: 350, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "alias", _showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true, contextMenuLabels:new List(contextMenuLabels), @@ -518,7 +518,7 @@ export class CurrentUserUtils { const reqdOpts:DocumentOptions = { _showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", system: true, isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, boxShadow: "0 0", childDontRegisterViews: true, - treeViewTruncateTitleWidth: 150, ignoreClick: true, childDropAction: "alias", + treeViewTruncateTitleWidth: 350, ignoreClick: true, childDropAction: "alias", childContextMenuLabels: new List(["Create new folder"]), childContextMenuIcons: new List(["plus"]), explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." @@ -535,7 +535,7 @@ export class CurrentUserUtils { static setupRecentlyClosed(doc: Doc, field:string) { const reqdOpts:DocumentOptions = { _showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "alias", system: true, - treeViewTruncateTitleWidth: 150, ignoreClick: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", + treeViewTruncateTitleWidth: 350, ignoreClick: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", contextMenuLabels: new List(["Empty recently closed"]), contextMenuIcons:new List(["trash"]), explainer: "Recently closed documents appear in this menu. They will only be deleted if you explicity empty this list." @@ -561,7 +561,7 @@ export class CurrentUserUtils { const reqdOpts:DocumentOptions = { _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view", boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, system: true, - treeViewHideTitle: true, treeViewTruncateTitleWidth: 150 + treeViewHideTitle: true, treeViewTruncateTitleWidth: 350 }; if (!doc[field]) DocUtils.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" }); return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, [doc]); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 10517d829..06eb6c6d7 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -112,7 +112,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } } //@ts-ignore - const titleField = +this._accumulatedTitle === this._accumulatedTitle ? +this._accumulatedTitle : this._accumulatedTitle; + const titleField = +this._accumulatedTitle == this._accumulatedTitle ? +this._accumulatedTitle : this._accumulatedTitle; Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true); if (d.rootDoc.syncLayoutFieldWithTitle) { @@ -345,7 +345,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 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.rootDoc._jitterRotation) / 180) * Math.PI); + const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.rootDoc._rotation) / 180) * Math.PI); seldocview.rootDoc.rotateCenterX = final.x / NumCast(seldocview.layoutDoc._width); seldocview.rootDoc.rotateCenterY = final.y / NumCast(seldocview.layoutDoc._height); }; @@ -381,7 +381,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const infos = new Map(); const seldocview = SelectionManager.Views()[0]; SelectionManager.Views().forEach(dv => { - const accumRot = (NumCast(dv.rootDoc._jitterRotation) / 180) * Math.PI; + const accumRot = (NumCast(dv.rootDoc._rotation) / 180) * Math.PI; const localRotCtr = dv.props.ScreenToLocalTransform().transformPoint(rcScreen.X, rcScreen.Y); const localRotCtrOffset = [localRotCtr[0] - NumCast(dv.rootDoc.width) / 2, localRotCtr[1] - NumCast(dv.rootDoc.height) / 2]; const startRotCtr = Utils.rotPt(localRotCtrOffset[0], localRotCtrOffset[1], -accumRot); @@ -396,7 +396,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P infos.set(dv.rootDoc, { unrotatedDocPos, startRotCtr, accumRot: isAbs ? angle : accumRot + angle }); dv.rootDoc.x = infos.get(dv.rootDoc)!.unrotatedDocPos.x - (endRotCtr.x - startRotCtr.x); dv.rootDoc.y = infos.get(dv.rootDoc)!.unrotatedDocPos.y - (endRotCtr.y - startRotCtr.y); - dv.rootDoc._jitterRotation = ((isAbs ? 0 : NumCast(dv.rootDoc._jitterRotation)) + (angle * 180) / Math.PI) % 360; // Rotation between -360 and 360 + dv.rootDoc._rotation = ((isAbs ? 0 : NumCast(dv.rootDoc._rotation)) + (angle * 180) / Math.PI) % 360; // Rotation between -360 and 360 }) ); }; @@ -416,7 +416,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P return false; }, // moveEvent action(() => { - const oldRotation = NumCast(seldocview.rootDoc._jitterRotation); + const oldRotation = NumCast(seldocview.rootDoc._rotation); const diff = oldRotation - Math.round(oldRotation / 45) * 45; if (Math.abs(diff) < 5) { if (selectedInk.length) { @@ -611,7 +611,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } } else { const rotCtr = [NumCast(doc._width) / 2, NumCast(doc._height) / 2]; - const tlRotated = Utils.rotPt(-rotCtr[0], -rotCtr[1], (NumCast(doc._jitterRotation) / 180) * Math.PI); + const tlRotated = Utils.rotPt(-rotCtr[0], -rotCtr[1], (NumCast(doc._rotation) / 180) * Math.PI); const maxHeight = doc.nativHeightUnfrozen || !nheight ? 0 : Math.max(nheight, NumCast(doc.scrollHeight, NumCast(doc[docView.LayoutFieldKey + '-scrollHeight']))) * docView.NativeDimScaling(); dH && (doc._height = actualdH > maxHeight && maxHeight ? maxHeight : actualdH); @@ -619,7 +619,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P dH && (doc._autoHeight = false); const rotCtr2 = [NumCast(doc._width) / 2, NumCast(doc._height) / 2]; - const tlRotated2 = Utils.rotPt(-rotCtr2[0], -rotCtr2[1], (NumCast(doc._jitterRotation) / 180) * Math.PI); + 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]); } @@ -695,7 +695,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const loccenter = Utils.rotPt( NumCast(seldocview.rootDoc.rotateCenterX) * NumCast(seldocview.layoutDoc._width), NumCast(seldocview.rootDoc.rotateCenterY) * NumCast(seldocview.layoutDoc._height), - (NumCast(seldocview.rootDoc._jitterRotation) / 180) * Math.PI + (NumCast(seldocview.rootDoc._rotation) / 180) * Math.PI ); return seldocview.props .ScreenToLocalTransform() @@ -783,7 +783,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P 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 useRotation = seldocview.rootDoc.type !== DocumentType.EQUATION; // when do we want an object to not rotate? - const rotation = NumCast(seldocview.rootDoc._jitterRotation); + const rotation = NumCast(seldocview.rootDoc._rotation); const resizerScheme = colorScheme ? 'documentDecorations-resizer' + colorScheme : ''; diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index bd6cea28a..22b0380a2 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -289,29 +289,29 @@ export class LightboxView extends React.Component { })} Document={LightboxView.LightboxDoc} DataDoc={undefined} + PanelWidth={this.lightboxWidth} + PanelHeight={this.lightboxHeight} LayoutTemplate={LightboxView.LightboxDocTemplate} - addDocument={undefined} isDocumentActive={returnFalse} isContentActive={returnTrue} - addDocTab={this.addDocTab} - pinToPres={TabDocView.PinDoc} - onBrowseClick={MainView.Instance.exploreMode} + styleProvider={DefaultStyleProvider} + ScreenToLocalTransform={this.lightboxScreenToLocal} + renderDepth={0} rootSelected={returnTrue} docViewPath={returnEmptyDoclist} docFilters={this.docFilters} - removeDocument={undefined} - styleProvider={DefaultStyleProvider} - ScreenToLocalTransform={this.lightboxScreenToLocal} - PanelWidth={this.lightboxWidth} - PanelHeight={this.lightboxHeight} - focus={DocUtils.DefaultFocus} - whenChildContentsActiveChanged={emptyFunction} - bringToFront={emptyFunction} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} - renderDepth={0} + addDocument={undefined} + removeDocument={undefined} + whenChildContentsActiveChanged={emptyFunction} + addDocTab={this.addDocTab} + pinToPres={TabDocView.PinDoc} + bringToFront={emptyFunction} + onBrowseClick={MainView.Instance.exploreMode} + focus={DocUtils.DefaultFocus} />
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 03c0642ed..4dc1ebd99 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -647,6 +647,7 @@ export class MainView extends React.Component { e.preventDefault(); }} style={{ + width: `calc(100% - ${this._leftMenuFlyoutWidth + this.leftMenuWidth() + this.propertiesWidth()}px)`, minWidth: `calc(100% - ${this._leftMenuFlyoutWidth + this.leftMenuWidth() + this.propertiesWidth()}px)`, transform: LightboxView.LightboxDoc ? 'scale(0.0001)' : undefined, }}> diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 2eb3dd532..bc8bd7b7f 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -85,7 +85,6 @@ export function DefaultStyleProvider(doc: Opt, props: Opt doc && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === 'comic'; const isBackground = () => doc && BoolCast(doc._lockedPosition); const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor); const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity); @@ -167,11 +166,11 @@ export function DefaultStyleProvider(doc: Opt, props: Opt (props?.PanelHeight() || 0) ? 5 : 10) : 0; + return Doc.IsComicStyle(doc) ? random(-1, 1, NumCast(doc?.x), NumCast(doc?.y)) * ((props?.PanelWidth() || 0) > (props?.PanelHeight() || 0) ? 5 : 10) : 0; case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.NoteTaking, CollectionViewType.Masonry, CollectionViewType.Tree].includes(doc?._viewType as any) || (doc?.type === DocumentType.RTF && !showTitle()?.includes('noMargin')) || diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index ba29b1d6f..77b47ed82 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -350,6 +350,8 @@ export class CollectionStackingView extends CollectionSubView = new Set(); // list of tree view items to monitor for height changes private observer: any; // observer for monitoring tree view items. - private static expandViewLabelSize = 20; @computed get doc() { return this.props.Document; @@ -100,7 +99,10 @@ export class CollectionTreeView extends CollectionSubView disposer?.()); } + shrinkWrap = () => {}; // placeholder to allow setContentView to work + componentDidMount() { + //this.props.setContentView?.(this); this._disposers.autoheight = reaction( () => this.rootDoc.autoHeight, auto => auto && this.computeHeight(), @@ -197,9 +199,7 @@ export class CollectionTreeView extends CollectionSubView void) => this.onExternalDrop(e, {}, addDocs); @undoBatch - makeTextCollection = (childDocs: Doc[]) => { - this.addDoc(TreeView.makeTextBullet(), childDocs.length ? childDocs[0] : undefined, true); - }; + makeTextCollection = (childDocs: Doc[]) => this.addDoc(TreeView.makeTextBullet(), childDocs.length ? childDocs[0] : undefined, true); get editableTitle() { return ( @@ -258,6 +258,7 @@ export class CollectionTreeView extends CollectionSubView ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); }; + headerFields = () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields); @computed get treeViewElements() { TraceMobx(); const dropAction = StrCast(this.doc.childDropAction) as dropActionType; @@ -281,7 +282,7 @@ export class CollectionTreeView extends CollectionSubView this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields), + this.headerFields, [], this.props.onCheckedClick, this.onChildClick, @@ -304,7 +305,7 @@ export class CollectionTreeView extends CollectionSubView (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this.props.ScreenToLocalTransform().Scale))} key={this.doc[Id]} - style={!this.outlineMode ? { paddingLeft: this.marginX(), paddingTop: this.marginTop() } : {}}> + style={!this.outlineMode ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}}> {this.outlineMode ? this.documentTitle : this.editableTitle}
); @@ -372,7 +373,7 @@ export class CollectionTreeView extends CollectionSubView (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.autoHeightMargins); truncateTitleWidth = () => this.treeViewtruncateTitleWidth; onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick); - panelWidth = () => Math.max(0, this.props.PanelWidth() - this.marginX() - CollectionTreeView.expandViewLabelSize) * (this.props.NativeDimScaling?.() || 1); + panelWidth = () => Math.max(0, this.props.PanelWidth() - 2 * this.marginX() * (this.props.NativeDimScaling?.() || 1)); addAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.addDocument(doc, `${this.props.fieldKey}-annotations`) || false; remAnnotationDocument = (doc: Doc | Doc[]) => this.props.CollectionView?.removeDocument(doc, `${this.props.fieldKey}-annotations`) || false; @@ -396,7 +397,7 @@ export class CollectionTreeView extends CollectionSubView @@ -432,24 +431,29 @@ export class CollectionTreeView extends CollectionSubView - {this.contentFunc} - - ) : ( - this.contentFunc() + const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1) || 1; + return ( +
+ {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? ( + + {this.contentFunc} + + ) : ( + this.contentFunc() + )} +
); } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index dcaad5632..9f63a11aa 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -54,6 +54,8 @@ interface CollectionViewProps_ extends FieldViewProps { childHideDecorationTitle?: () => boolean; childHideResizeHandles?: () => boolean; childLayoutTemplate?: () => Doc | undefined; // specify a layout Doc template to use for children of the collection + childXPadding?: number; + childYPadding?: number; childLayoutString?: string; childIgnoreNativeSize?: boolean; childClickScript?: ScriptField; diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index a6cfbd6b2..cde5132a3 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -256,7 +256,6 @@ export class TabDocView extends React.Component { pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. pinDoc.treeViewFieldKey = '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.treeViewExpandedView = '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.treeViewGrowsHorizontally = true; // the document expands horizontally when displayed as a tree view header pinDoc.treeViewHideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header const presArray: Doc[] = PresBox.Instance?.sortArray(); const size: number = PresBox.Instance?.selectedArray.size; diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index 57bb5274d..83fee013a 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -24,6 +24,7 @@ // width: $TREE_BULLET_WIDTH; width: 100%; height: 100%; + position: absolute; .treeView-expandIcon { display: none; @@ -118,7 +119,7 @@ display: flex; // needed for PresBox's treeView border: transparent 1px solid; align-items: center; - width: 100%; + width: max-content; border-radius: 5px; &:hover { diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index b9f86fa6b..1e97eee37 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -10,7 +10,7 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, simulateMouseClick, Utils } from '../../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; @@ -321,6 +321,7 @@ export class TreeView extends React.Component { _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, + _fitWidth: true, treeViewType: TreeViewType.outline, x: 0, y: 0, @@ -398,29 +399,22 @@ export class TreeView extends React.Component { }; docTransform = () => this.refTransform(this._dref?.ContentRef?.current); getTransform = () => this.refTransform(this._tref.current); - docWidth = () => { - const layoutDoc = this.layoutDoc; - const aspect = Doc.NativeAspect(layoutDoc); - if (layoutDoc._fitWidth) return Math.min(this.props.panelWidth() - treeBulletWidth(), layoutDoc[WidthSym]()); - if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.panelWidth() - treeBulletWidth())); - return Math.min((this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.NativeDimScaling?.() || 1), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]()); - }; - docHeight = () => { - const layoutDoc = this.layoutDoc; - return Math.max( - 70, - Math.min( - this.MAX_EMBED_HEIGHT, - (() => { - const aspect = Doc.NativeAspect(layoutDoc); - if (aspect) return this.docWidth() / (aspect || 1); - return layoutDoc._fitWidth - ? !Doc.NativeHeight(this.doc) - ? NumCast(this.props.containerCollection._height) - : Math.min((this.docWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containerCollection._height))) - : layoutDoc[HeightSym]() || 50; - })() - ) + embeddedPanelWidth = () => this.props.panelWidth() / (this.props.treeView.props.NativeDimScaling?.() || 1); + embeddedPanelHeight = () => { + console.log(this.props.treeView.rootDoc.title); + const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc; + return Math.min( + layoutDoc[HeightSym](), + this.MAX_EMBED_HEIGHT, + (() => { + const aspect = Doc.NativeAspect(layoutDoc); + if (aspect) return this.embeddedPanelWidth() / (aspect || 1); + return layoutDoc._fitWidth + ? !Doc.NativeHeight(layoutDoc) + ? NumCast(layoutDoc._height) //this.props.containerCollection._height) + : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containerCollection._height))) + : (this.embeddedPanelWidth() * layoutDoc[HeightSym]()) / layoutDoc[WidthSym](); + })() ); }; @@ -512,28 +506,6 @@ export class TreeView extends React.Component { return rows; } - rtfWidth = () => { - const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc; - return Math.min(layout[WidthSym](), this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.NativeDimScaling?.() || 1); - }; - rtfHeight = () => { - const layout = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc; - return this.rtfWidth() <= layout[WidthSym]() ? Math.min(layout[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT; - }; - rtfOutlineHeight = () => Math.max(this.layoutDoc?.[HeightSym](), treeBulletWidth()); - expandPanelHeight = () => { - if (this.layoutDoc._fitWidth) return this.docHeight(); - const aspect = this.layoutDoc[WidthSym]() / this.layoutDoc[HeightSym](); - const docAspect = this.docWidth() / this.docHeight(); - return docAspect < aspect ? this.docWidth() / aspect : this.docHeight(); - }; - expandPanelWidth = () => { - if (this.layoutDoc._fitWidth) return this.docWidth(); - const aspect = this.layoutDoc[WidthSym]() / this.layoutDoc[HeightSym](); - const docAspect = this.docWidth() / this.docHeight(); - return docAspect > aspect ? this.docHeight() * aspect : this.docWidth(); - }; - @computed get renderContent() { TraceMobx(); const expandKey = this.treeViewExpandedView; @@ -792,15 +764,18 @@ export class TreeView extends React.Component { titleStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (!doc || doc !== this.doc) return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView + const treeView = this.props.treeView; // prettier-ignore switch (property.split(':')[0]) { case StyleProp.Opacity: return this.props.treeView.outlineMode ? undefined : 1; case StyleProp.BackgroundColor: return this.selected ? '#7089bb' : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); case StyleProp.Highlighting: if (this.props.treeView.outlineMode) return undefined; + case StyleProp.Hidden: return false; + case StyleProp.BoxShadow: return undefined; case StyleProp.DocContents: const highlightIndex = this.props.treeView.outlineMode ? Doc.DocBrushStatus.unbrushed : Doc.isBrushedHighlightedDegree(doc); const highlightColor = ['transparent', 'rgb(68, 118, 247)', 'rgb(68, 118, 247)', 'orange', 'lightBlue'][highlightIndex]; - return this.props.treeView.outlineMode ? null : ( + return treeView.outlineMode ? null : (
{ maxWidth: props?.PanelWidth() || undefined, background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor), outline: `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)), + paddingTop: treeView.props.childYPadding, + paddingBottom: treeView.props.childYPadding, }}> {StrCast(doc?.title)}
); } - return this.props?.treeView?.props.styleProvider?.(doc, props, property); + return treeView.props.styleProvider?.(doc, props, property); }; embeddedStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (property.startsWith(StyleProp.Decorations)) return null; + if (property.startsWith(StyleProp.Hidden)) return false; return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView }; onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { @@ -843,7 +823,7 @@ export class TreeView extends React.Component { } return false; }; - titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth() - 2 * treeBulletWidth())); + titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth())) / (this.props.treeView.props.NativeDimScaling?.() || 1) - 3 * treeBulletWidth(); return18 = () => 18; /** @@ -851,6 +831,7 @@ export class TreeView extends React.Component { */ @computed get renderTitle() { + // TraceMobx(); const view = this._editTitle ? ( { } })} Document={this.doc} + fitWidth={(doc: Doc) => true} DataDoc={undefined} scriptContext={this} hideDecorationTitle={this.props.treeView.outlineMode} @@ -905,7 +887,7 @@ export class TreeView extends React.Component { removeDocument={this.props.removeDoc} ScreenToLocalTransform={this.getTransform} NativeHeight={this.return18} - NativeWidth={this.titleWidth} + NativeWidth={returnZero} PanelWidth={this.titleWidth} PanelHeight={this.return18} contextMenuItems={this.contextMenuItems} @@ -918,10 +900,12 @@ export class TreeView extends React.Component { disableDocBrushing={this.props.treeView.props.disableDocBrushing} hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)} dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)} + xPadding={NumCast(this.props.treeView.props.Document.childXPadding, this.props.treeView.props.childXPadding)} + yPadding={NumCast(this.props.treeView.props.Document.childYPadding, this.props.treeView.props.childYPadding)} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} + ContainingCollectionView={this.props.treeView.props.CollectionView} ContainingCollectionDoc={this.props.treeView.props.Document} /> ); @@ -968,53 +952,52 @@ export class TreeView extends React.Component { }; renderEmbeddedDocument = (asText: boolean, isActive: () => boolean | undefined) => { - const isExpandable = this.doc._treeViewGrowsHorizontally; - const panelWidth = asText || isExpandable ? this.rtfWidth : this.expandPanelWidth; - const panelHeight = asText ? this.rtfOutlineHeight : isExpandable ? this.rtfHeight : this.expandPanelHeight; return ( - (this._dref = r))} - Document={this.doc} - DataDoc={undefined} - PanelWidth={panelWidth} - PanelHeight={panelHeight} - NativeWidth={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfWidth : undefined} - NativeHeight={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfHeight : undefined} - LayoutTemplateString={asText ? FormattedTextBox.LayoutString('text') : undefined} - LayoutTemplate={this.props.treeView.props.childLayoutTemplate} - isContentActive={isActive} - isDocumentActive={isActive} - styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider} - hideTitle={asText} - fitContentsToBox={returnTrue} - hideDecorationTitle={this.props.treeView.outlineMode} - hideResizeHandles={this.props.treeView.outlineMode} - onClick={this.onChildClick} - focus={this.refocus} - onKey={this.onKeyDown} - hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)} - dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)} - ScreenToLocalTransform={this.docTransform} - renderDepth={this.props.renderDepth + 1} - treeViewDoc={this.props.treeView?.props.Document} - rootSelected={returnTrue} - docViewPath={this.props.treeView.props.docViewPath} - docFilters={returnEmptyFilter} - docRangeFilters={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - ContainingCollectionDoc={this.props.containerCollection} - ContainingCollectionView={undefined} - addDocument={this.props.addDocument} - moveDocument={this.move} - removeDocument={this.props.removeDoc} - whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} - addDocTab={this.props.addDocTab} - pinToPres={this.props.treeView.props.pinToPres} - disableDocBrushing={this.props.treeView.props.disableDocBrushing} - bringToFront={returnFalse} - scriptContext={this} - /> +
+ (this._dref = r))} + Document={this.doc} + DataDoc={undefined} + PanelWidth={this.embeddedPanelWidth} + PanelHeight={this.embeddedPanelHeight} + LayoutTemplateString={asText ? FormattedTextBox.LayoutString('text') : undefined} + LayoutTemplate={this.props.treeView.props.childLayoutTemplate} + isContentActive={isActive} + isDocumentActive={isActive} + styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider} + hideTitle={asText} + //fitContentsToBox={returnTrue} + hideDecorationTitle={this.props.treeView.outlineMode} + hideResizeHandles={this.props.treeView.outlineMode} + onClick={this.onChildClick} + focus={this.refocus} + onKey={this.onKeyDown} + hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)} + dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)} + ScreenToLocalTransform={this.docTransform} + renderDepth={this.props.renderDepth + 1} + treeViewDoc={this.props.treeView?.props.Document} + rootSelected={returnTrue} + docViewPath={this.props.treeView.props.docViewPath} + docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} + ContainingCollectionDoc={this.props.containerCollection} + ContainingCollectionView={undefined} + addDocument={this.props.addDocument} + moveDocument={this.move} + removeDocument={this.props.removeDoc} + whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} + xPadding={NumCast(this.props.treeView.props.Document.childXPadding, this.props.treeView.props.childXPadding)} + yPadding={NumCast(this.props.treeView.props.Document.childYPadding, this.props.treeView.props.childYPadding)} + addDocTab={this.props.addDocTab} + pinToPres={this.props.treeView.props.pinToPres} + disableDocBrushing={this.props.treeView.props.disableDocBrushing} + bringToFront={returnFalse} + scriptContext={this} + /> +
); }; @@ -1148,7 +1131,7 @@ export class TreeView extends React.Component { } const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion, TreeSort.None)); - const rowWidth = () => panelWidth() - treeBulletWidth(); + const rowWidth = () => panelWidth() - treeBulletWidth() * (treeView.props.NativeDimScaling?.() || 1); const treeViewRefs = new Map(); return docs .filter(child => child instanceof Doc) diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 559951efc..2f246e74f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1317,7 +1317,7 @@ export class CollectionFreeFormView extends CollectionSubView ); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 04c7b96e3..260c98816 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -25,7 +25,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { renderCutoffProvider: (doc: Doc) => boolean; zIndex?: number; highlight?: boolean; - jitterRotation: number; + rotation: number; dataTransition?: string; replica: string; CollectionFreeFormView: CollectionFreeFormView; @@ -38,7 +38,7 @@ export class CollectionFreeFormDocumentView extends DocComponent void; ScreenToLocalTransform: () => Transform; bringToFront: (doc: Doc, sendToBack?: boolean) => void; + xPadding?: number; + yPadding?: number; dropAction?: dropActionType; dontRegisterView?: boolean; hideLinkButton?: boolean; @@ -1349,17 +1352,10 @@ export class DocumentViewInternal extends DocComponent - {!this.headerMargin ? ( - <> - {' '} - {this.contents} {titleView}{' '} - - ) : ( - <> - {' '} - {titleView} {this.contents}{' '} - - )} + {' '} + {!this.headerMargin ? this.contents : titleView} + {!this.headerMargin ? titleView : this.contents} + {' ' /* */} {captionView}
); @@ -1372,7 +1368,7 @@ export class DocumentViewInternal extends DocComponent {animRenderDoc}
- +
@@ -1552,7 +1548,7 @@ export class DocumentView extends React.Component { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.fitWidth)); } @computed get shouldNotScale() { - return (this.fitWidth && !this.nativeWidth) || this.props.dontScaleFilter?.(this.Document) || this.props.treeViewDoc || [CollectionViewType.Docking].includes(this.Document._viewType as any); + return (this.fitWidth && !this.nativeWidth) || this.props.dontScaleFilter?.(this.Document) || [CollectionViewType.Docking].includes(this.Document._viewType as any); } @computed get effectiveNativeWidth() { return this.shouldNotScale ? 0 : this.nativeWidth || NumCast(this.layoutDoc.width); @@ -1597,7 +1593,7 @@ export class DocumentView extends React.Component { toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); focus = (doc: Doc, options: DocFocusOptions) => this.docView?.focus(doc, options); getBounds = () => { - if (!this.docView || !this.docView.ContentDiv || this.props.Document.presBox || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { + if (!this.docView || !this.docView.ContentDiv || this.props.Document.presBox || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { return undefined; } const xf = this.docView?.props.ScreenToLocalTransform().scale(this.nativeScaling).inverse(); @@ -1687,10 +1683,9 @@ export class DocumentView extends React.Component { render() { TraceMobx(); - const xshift = () => (Math.abs(this.Xshift) <= 0.001 ? this.props.PanelWidth() : undefined); - const yshift = () => (Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined); - const isPresTreeElement: boolean = this.props.treeViewDoc?.type === DocumentType.PRES; - const isButton: boolean = this.props.Document.type === DocumentType.FONTICON || this.props.Document._viewType === CollectionViewType.Linear; + const xshift = Math.abs(this.Xshift) <= 0.001 ? this.props.PanelWidth() : undefined; + const yshift = Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined; + const isButton = this.props.Document.type === DocumentType.FONTICON || this.props.Document._viewType === CollectionViewType.Linear; return (
{!this.props.Document || !this.props.PanelWidth() ? null : ( @@ -1700,11 +1695,11 @@ export class DocumentView extends React.Component { style={{ transition: this.props.dataTransition, transform: isButton ? undefined : `translate(${this.centeringX}px, ${this.centeringY}px)`, - width: isButton || isPresTreeElement ? '100%' : xshift() ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`, + width: isButton ? '100%' : xshift ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`, height: isButton || this.props.forceAutoHeight ? undefined - : yshift() ?? (this.fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`), + : yshift ?? (this.fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`), }}> this.autoHeight, autoHeight => autoHeight && this.tryUpdateScrollHeight() ); + this._disposers.width = reaction( + () => this.props.PanelWidth(), + width => this.tryUpdateScrollHeight() + ); this._disposers.scrollHeight = reaction( () => ({ scrollHeight: this.scrollHeight, autoHeight: this.autoHeight, width: NumCast(this.layoutDoc._width) }), - ({ width, scrollHeight, autoHeight }) => { - width && autoHeight && this.resetNativeHeight(scrollHeight); - }, + ({ width, scrollHeight, autoHeight }) => width && autoHeight && this.resetNativeHeight(scrollHeight), { fireImmediately: true } ); this._disposers.componentHeights = reaction( diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 258dad39c..4e8aed8a6 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -429,7 +429,7 @@ export class PresBox extends ViewBoxBaseComponent() { pinDoc.presPinLayout = true; pinDoc.presX = NumCast(targetDoc.x); pinDoc.presY = NumCast(targetDoc.y); - pinDoc.presRot = NumCast(targetDoc.jitterRotation); + pinDoc.presRot = NumCast(targetDoc.rotation); pinDoc.presWidth = NumCast(targetDoc.width); pinDoc.presHeight = NumCast(targetDoc.height); } @@ -521,7 +521,7 @@ export class PresBox extends ViewBoxBaseComponent() { targetDoc._dataTransition = presTransitionTime; targetDoc.x = NumCast(activeItem.presX, NumCast(targetDoc.x)); targetDoc.y = NumCast(activeItem.presY, NumCast(targetDoc.y)); - targetDoc.jitterRotation = NumCast(activeItem.presRot, NumCast(targetDoc.jitterRotation)); + targetDoc.rotation = NumCast(activeItem.presRot, NumCast(targetDoc.rotation)); targetDoc.width = NumCast(activeItem.presWidth, NumCast(targetDoc.width)); targetDoc.height = NumCast(activeItem.presHeight, NumCast(targetDoc.height)); setTimeout(() => (targetDoc._dataTransition = undefined), transTime + 10); @@ -2652,9 +2652,10 @@ export class PresBox extends ViewBoxBaseComponent() { PanelHeight={this.panelHeight} childIgnoreNativeSize={true} moveDocument={returnFalse} - childFitWidth={returnTrue} + //childFitWidth={returnTrue} childOpacity={returnOne} childLayoutTemplate={this.childLayoutTemplate} + childXPadding={Doc.IsComicStyle(this.rootDoc) ? 20 : undefined} filterAddDocument={this.addDocumentFilter} removeDocument={returnFalse} dontRegisterView={true} diff --git a/src/client/views/nodes/trails/PresElementBox.scss b/src/client/views/nodes/trails/PresElementBox.scss index 8a6c2a6dc..415253af1 100644 --- a/src/client/views/nodes/trails/PresElementBox.scss +++ b/src/client/views/nodes/trails/PresElementBox.scss @@ -42,10 +42,7 @@ $slide-active: #5b9fdd; width: 100%; border-bottom: 0.5px solid grey; display: flex; - justify-content: space-between; align-items: center; - grid-template-rows: 16px 10px auto; - grid-template-columns: max-content max-content max-content max-content auto; .presItem-name { display: flex; @@ -102,13 +99,7 @@ $slide-active: #5b9fdd; grid-row: 3; grid-column: 1/8; position: relative; - display: flex; - width: auto; - justify-content: center; - margin: auto; - margin-bottom: 2px; - border-bottom-left-radius: 5px; - border-bottom-right-radius: 5px; + display: inline-block; } .presItem-embeddedMask { @@ -124,8 +115,7 @@ $slide-active: #5b9fdd; .presItem-slideButtons { display: flex; - grid-column: 7; - grid-row: 1/3; + position: absolute; width: max-content; justify-self: right; justify-content: flex-end; diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index f4ab845f3..5d14a0e9a 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -4,7 +4,9 @@ import { action, computed, IReactionDisposer, observable, reaction } from 'mobx' import { observer } from 'mobx-react'; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../../fields/Doc'; import { Copy, Id } from '../../../../fields/FieldSymbols'; +import { InkField } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; +import { RichTextField } from '../../../../fields/RichTextField'; import { Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils'; import { Docs, DocUtils } from '../../../documents/Documents'; @@ -14,6 +16,7 @@ import { DragManager } from '../../../util/DragManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; +import { MarqueeView } from '../../collections/collectionFreeForm'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; @@ -24,9 +27,6 @@ import { PresBox } from './PresBox'; import './PresElementBox.scss'; import { PresMovement } from './PresEnums'; import React = require('react'); -import { InkField } from '../../../../fields/InkField'; -import { RichTextField } from '../../../../fields/RichTextField'; -import { MarqueeView } from '../../collections/collectionFreeForm'; /** * This class models the view a document added to presentation will have in the presentation. * It involves some functionality for its buttons and options. @@ -44,8 +44,11 @@ export class PresElementBox extends ViewBoxBaseComponent() { @computed get indexInPres() { return DocListCast(this.presBox[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc); } // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements) + @computed get expandViewHeight() { + return 100; + } @computed get collapsedHeight() { - return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(this.presBox._viewType as any) ? 35 : 31; + return 35; } // the collapsed height changes depending on the state of the presBox. We could store this on the presentation element template if it's used by only one presentation - but if it's shared by multiple, then this value must be looked up @computed get presStatus() { return this.presBox.presStatus; @@ -58,7 +61,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as PresBox) : undefined; } @computed get presBox() { - return (this.props.DocumentView?.().props.treeViewDoc ?? this.props.ContainingCollectionDoc)!; + return this.props.ContainingCollectionDoc!; } @computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; @@ -67,8 +70,8 @@ export class PresElementBox extends ViewBoxBaseComponent() { componentDidMount() { this.layoutDoc.hideLinkButton = true; this._heightDisposer = reaction( - () => [this.rootDoc.presExpandInlineButton, this.collapsedHeight], - params => (this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0)), + () => ({ expand: this.rootDoc.presExpandInlineButton, height: this.collapsedHeight }), + ({ expand, height }) => (this.layoutDoc._height = height + (expand ? this.expandViewHeight : 0)), { fireImmediately: true } ); } @@ -84,10 +87,10 @@ export class PresElementBox extends ViewBoxBaseComponent() { @action presExpandDocumentClick = () => (this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton); - embedHeight = (): number => 97; + embedHeight = (): number => this.collapsedHeight + this.expandViewHeight; // embedWidth = () => this.props.PanelWidth(); // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight); - embedWidth = (): number => this.props.PanelWidth() - 35; + embedWidth = (): number => this.props.PanelWidth() / 2; styleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (property === StyleProp.Opacity) return 1; return this.props.styleProvider?.(doc, props, property); @@ -98,35 +101,35 @@ export class PresElementBox extends ViewBoxBaseComponent() { */ @computed get renderEmbeddedInline() { return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? null : ( -
+
-
+ {/*
*/}
); } @@ -206,8 +209,8 @@ export class PresElementBox extends ViewBoxBaseComponent() { const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []); if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc); dragData.dropAction = 'move'; - dragData.treeViewDoc = this.props.docViewPath().lastElement()?.props.treeViewDoc; - dragData.moveDocument = this.props.docViewPath().lastElement()?.props.moveDocument; + dragData.treeViewDoc = this.presBox._viewType === CollectionViewType.Tree ? this.props.ContainingCollectionDoc : undefined; // this.props.DocumentView?.()?.props.treeViewDoc; + dragData.moveDocument = this.props.moveDocument; const dragItem: HTMLElement[] = []; if (dragArray.length === 1) { const doc = this._itemRef.current || dragArray[0]; @@ -307,7 +310,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { updateCapturedContainerLayout = (targetDoc: Doc, activeItem: Doc) => { activeItem.presX = NumCast(targetDoc.x); activeItem.presY = NumCast(targetDoc.y); - activeItem.presRot = NumCast(targetDoc.jitterRotation); + activeItem.presRot = NumCast(targetDoc.rotation); activeItem.presWidth = NumCast(targetDoc.width); activeItem.presHeight = NumCast(targetDoc.height); }; @@ -464,16 +467,90 @@ export class PresElementBox extends ViewBoxBaseComponent() { return width; } + @computed get presButtons() { + const presBox: Doc = this.presBox; //presBox + const presBoxColor: string = StrCast(presBox._backgroundColor); + const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false; + const targetDoc: Doc = this.targetDoc; + const activeItem: Doc = this.rootDoc; + + const items: JSX.Element[] = []; + if (activeItem.presPinLayout) { + items.push( + Update captured doc layout
}> +
this.updateCapturedContainerLayout(targetDoc, activeItem)} style={{ fontWeight: 700, display: 'flex' }}> + L +
+ + ); + } + if (activeItem.presPinData || activeItem.presPinView) { + items.push( + Update captured doc content
}> +
this.updateCapturedViewContents(targetDoc, activeItem)} style={{ fontWeight: 700, display: 'flex' }}> + C +
+ + ); + } + if (!Doc.noviceMode) { + items.push( + {this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}
}> +
(this.recordingIsInOverlay ? this.hideRecording(e, true) : this.startRecording(e, activeItem))} style={{ fontWeight: 700 }}> + e.stopPropagation()} /> +
+ + ); + } + if (this.indexInPres === 0) { + items.push( + {activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}
}> +
(activeItem.groupWithUp = !activeItem.groupWithUp)} + style={{ + zIndex: 1000 - this.indexInPres, + fontWeight: 700, + backgroundColor: activeItem.groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined, + height: activeItem.groupWithUp ? 53 : 18, + transform: activeItem.groupWithUp ? 'translate(0, -17px)' : undefined, + }}> +
+ e.stopPropagation()} /> +
+
+ + ); + } + items.push( + {this.rootDoc.presExpandInlineButton ? 'Minimize' : 'Expand'}
}> +
{ + e.stopPropagation(); + this.presExpandDocumentClick(); + }}> + e.stopPropagation()} /> +
+ + ); + items.push( + Remove from presentation
}> +
+ e.stopPropagation()} /> +
+ + ); + return items; + } + @computed get mainItem() { const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false; const isCurrent: boolean = this.presBox._itemIndex === this.indexInPres; - const toolbarWidth: number = this.toolbarWidth; - const showMore: boolean = this.toolbarWidth >= 300; const miniView: boolean = this.toolbarWidth <= 110; const presBox: Doc = this.presBox; //presBox const presBoxColor: string = StrCast(presBox._backgroundColor); const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false; - const targetDoc: Doc = this.targetDoc; const activeItem: Doc = this.rootDoc; return ( @@ -484,6 +561,10 @@ export class PresElementBox extends ViewBoxBaseComponent() { style={{ backgroundColor: presColorBool ? (isSelected ? 'rgba(250,250,250,0.3)' : 'transparent') : isSelected ? Colors.LIGHT_BLUE : 'transparent', opacity: this._dragging ? 0.3 : 1, + paddingLeft: NumCast(this.layoutDoc._xPadding, this.props.xPadding), + paddingRight: NumCast(this.layoutDoc._xPadding, this.props.xPadding), + paddingTop: NumCast(this.layoutDoc._yPadding, this.props.yPadding), + paddingBottom: NumCast(this.layoutDoc._yPadding, this.props.yPadding), }} onClick={e => { e.stopPropagation(); @@ -507,6 +588,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { ref={this._dragRef} className={`presItem-slide ${isCurrent ? 'active' : ''}`} style={{ + display: 'infline-block', backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor), //boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined, border: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? presBoxColor + ' solid 2.5px' : undefined) : undefined, @@ -514,8 +596,9 @@ export class PresElementBox extends ViewBoxBaseComponent() {
{`${this.indexInPres + 1}. `}
@@ -523,56 +606,8 @@ export class PresElementBox extends ViewBoxBaseComponent() {
{/*
{"Movement speed"}
}>
{this.transition}
*/} {/*
{"Duration"}
}>
{this.duration}
*/} -
- Update captured doc layout
}> -
this.updateCapturedContainerLayout(targetDoc, activeItem)} style={{ fontWeight: 700, display: activeItem.presPinLayout ? 'flex' : 'none' }}> - L -
- - Update captured doc content
}> -
this.updateCapturedViewContents(targetDoc, activeItem)} style={{ fontWeight: 700, display: activeItem.presPinData || activeItem.presPinView ? 'flex' : 'none' }}> - C -
- - {!Doc.noviceMode && ( - {this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}
}> -
(this.recordingIsInOverlay ? this.hideRecording(e, true) : this.startRecording(e, activeItem))} style={{ fontWeight: 700 }}> - e.stopPropagation()} /> -
- - )} - {activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}
}> -
(activeItem.groupWithUp = !activeItem.groupWithUp)} - style={{ - display: this.indexInPres === 0 ? 'none' : '', - zIndex: 1000 - this.indexInPres, - fontWeight: 700, - backgroundColor: activeItem.groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined, - height: activeItem.groupWithUp ? 53 : 18, - transform: activeItem.groupWithUp ? 'translate(0, -17px)' : undefined, - }}> -
- e.stopPropagation()} /> -
-
- - {this.rootDoc.presExpandInlineButton ? 'Minimize' : 'Expand'}
}> -
{ - e.stopPropagation(); - this.presExpandDocumentClick(); - }}> - e.stopPropagation()} /> -
- - Remove from presentation
}> -
- e.stopPropagation()} /> -
- +
+ {...this.presButtons}
{this.renderEmbeddedInline}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 466b43287..fc43325fe 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -238,6 +238,9 @@ export class Doc extends RefField { Doc.UserDoc().activePage = val; DocServer.UPDATE_SERVER_CACHE(); } + public static IsComicStyle(doc?: Doc) { + return doc && Doc.ActiveDashboard && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === 'comic'; + } public static get ActiveDashboard() { return DocCast(Doc.UserDoc().activeDashboard); } -- cgit v1.2.3-70-g09d2 From 13002bb819e54f3e2f2d25c4b043abf1c15386bb Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 9 Nov 2022 12:22:04 -0500 Subject: fixed treeViews again to make room for hover buttons properly. fixed copying text from pdf to highlight copied regions without always displaying anchor. --- src/client/util/CurrentUserUtils.ts | 8 ++++---- src/client/views/LightboxView.tsx | 2 +- .../views/collections/CollectionTreeView.scss | 3 ++- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/TreeView.scss | 3 ++- src/client/views/collections/TreeView.tsx | 24 ++++++++++++++-------- src/client/views/pdf/Annotation.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 2 ++ src/fields/util.ts | 1 - 9 files changed, 29 insertions(+), 18 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 114dbac93..f2d851a40 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -214,7 +214,7 @@ export class CurrentUserUtils { title: string, toolTip: string, icon: string, ignoreClick?: boolean, dragFactory?: Doc, backgroundColor?: string, clickFactory?: Doc, scripts?: { onClick?: string, onDragStart?: string}, funcs?: {onDragStart?:string, hidden?: string}, }[] { - const standardOps = (key:string) => ({ title : "Untitled "+ key, _fitWidth: true, system: true, "dragFactory-count": 0, cloneFieldFilter: new List(["system"]) }); + const standardOps = (key:string) => ({ title : "Untitled "+ key, _fitWidth: false, system: true, "dragFactory-count": 0, cloneFieldFilter: new List(["system"]) }); const json = { doc: { type: "doc", @@ -260,7 +260,7 @@ export class CurrentUserUtils { {key: "Note", creator: opts => Docs.Create.TextDocument("", opts), opts: { _width: 200, _autoHeight: true }}, {key: "Noteboard", creator: opts => Docs.Create.NoteTakingDocument([], opts), opts: { _width: 250, _height: 200 }}, {key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100 }}, - {key: "Equation", creator: opts => Docs.Create.EquationDocument(opts), opts: { _width: 300, _height: 35, _fitWidth:false, _backgroundGridShow: true, }}, + {key: "Equation", creator: opts => Docs.Create.EquationDocument(opts), opts: { _width: 300, _height: 35, _backgroundGridShow: true, }}, {key: "Webpage", creator: opts => Docs.Create.WebDocument("",opts), opts: { _width: 400, _height: 512, _nativeWidth: 850, useCors: true, }}, {key: "Comparison", creator: Docs.Create.ComparisonDocument, opts: { _width: 300, _height: 300 }}, {key: "Audio", creator: opts => Docs.Create.AudioDocument(nullAudio, opts),opts: { _width: 200, _height: 100, }}, @@ -271,8 +271,8 @@ export class CurrentUserUtils { {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, // {key: "DataViz", creator: opts => Docs.Create.DataVizDocument(opts), opts: { _width: 300, _height: 300 }}, {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true,}}, - {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _viewType: CollectionViewType.Stacking, targetDropAction: "alias" as any, treeViewHideTitle: true, _chromeHidden: true, boxShadow: "0 0" }}, - {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _backgroundGridShow: true, }}, + {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _viewType: CollectionViewType.Stacking, targetDropAction: "alias" as any, treeViewHideTitle: true, _fitWidth:true, _chromeHidden: true, boxShadow: "0 0" }}, + {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _fitWidth: true, _backgroundGridShow: true, }}, {key: "Slide", creator: opts => Docs.Create.TreeDocument([], opts), opts: { _width: 300, _height: 200, _viewType: CollectionViewType.Tree, treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, allowOverlayDrop: true, treeViewType: TreeViewType.outline, diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index a9fba3688..91773419a 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -292,7 +292,7 @@ export class LightboxView extends React.Component { PanelWidth={this.lightboxWidth} PanelHeight={this.lightboxHeight} LayoutTemplate={LightboxView.LightboxDocTemplate} - isDocumentActive={returnTrue} + isDocumentActive={returnTrue} // without this being true, sidebar annotations need to be activated before text can be selected. isContentActive={returnTrue} styleProvider={DefaultStyleProvider} ScreenToLocalTransform={this.lightboxScreenToLocal} diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 3785b7d61..273b08247 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -67,7 +67,8 @@ font-style: italic; font-size: 8pt; margin-left: 3px; - display: none; + opacity: 0; + pointer-events: none; } .collectionTreeView-contents { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 0ff89c5a7..1a265af4a 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -115,7 +115,7 @@ export class CollectionTreeView extends CollectionSubView p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()) + 6; this.layoutDoc._autoHeightMargins = bodyHeight; - this.props.setHeight?.(bodyHeight + titleHeight); + !this.props.dontRegisterView && this.props.setHeight?.(bodyHeight + titleHeight); } }; unobserveHeight = (ref: any) => { diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index 83fee013a..7eab03e1d 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -173,7 +173,8 @@ .treeView-header:hover { .collectionTreeView-keyHeader { - display: inherit; + opacity: unset; + pointer-events: unset; } .treeView-openRight { diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index ac8562d5a..13cf64558 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -416,7 +416,6 @@ export class TreeView extends React.Component { })() ); }; - @computed get expandedField() { const ids: { [key: string]: string } = {}; const rows: JSX.Element[] = []; @@ -428,6 +427,8 @@ export class TreeView extends React.Component { const contents = doc[key]; let contentElement: (JSX.Element | null)[] | JSX.Element = []; + let leftOffset = observable({ width: 0 }); + const expandedWidth = () => this.props.panelWidth() - leftOffset.width; if (contents instanceof Doc || (Cast(contents, listSpec(Doc)) && Cast(contents, listSpec(Doc))!.length && Cast(contents, listSpec(Doc))![0] instanceof Doc)) { const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key); const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => { @@ -452,7 +453,7 @@ export class TreeView extends React.Component { this.titleStyleProvider, this.props.ScreenToLocalTransform, this.props.isContentActive, - this.props.panelWidth, + expandedWidth, this.props.renderDepth, this.props.treeViewHideHeaderFields, [...this.props.renderedIds, doc[Id]], @@ -483,15 +484,21 @@ export class TreeView extends React.Component { ); } rows.push( -
- {key + ':'} -   +
+ { + if (r) leftOffset.width = r.getBoundingClientRect().width; + })} + style={{ fontWeight: 'bold' }}> + {key + ':'} +   + {contentElement}
); } rows.push( -
+
{ this.treeViewOpen = true; }; + @observable headerEleWidth = 0; @computed get headerElements() { return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : ( <> @@ -822,7 +830,7 @@ export class TreeView extends React.Component { } return false; }; - titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth())) / (this.props.treeView.props.NativeDimScaling?.() || 1) - 3 * treeBulletWidth(); + titleWidth = () => Math.max(20, Math.min(this.props.treeView.truncateTitleWidth(), this.props.panelWidth())) / (this.props.treeView.props.NativeDimScaling?.() || 1) - this.headerEleWidth - treeBulletWidth(); return18 = () => 18; /** @@ -923,7 +931,7 @@ export class TreeView extends React.Component { }}> {view}
-
+
r && (this.headerEleWidth = r.getBoundingClientRect().width))}> {buttons} {/* hide and lock buttons */} {this.headerElements}
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index ee418a02f..9af0949eb 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -22,7 +22,7 @@ interface IAnnotationProps extends FieldViewProps { export class Annotation extends React.Component { render() { return ( -
+
{DocListCast(this.props.anno.textInlineAnnotations).map(a => ( ))} diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 7f99c30e3..6ff87ef9f 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -133,6 +133,7 @@ export class PDFViewer extends React.Component { e.clipboardData.setData('text/plain', this._selectionText); const anchor = this._getAnchor(); if (anchor) { + anchor.textCopied = true; e.clipboardData.setData('dash/pdfAnchor', anchor[Id]); } e.preventDefault(); @@ -473,6 +474,7 @@ export class PDFViewer extends React.Component {
{this.inlineTextAnnotations .sort((a, b) => NumCast(a.y) - NumCast(b.y)) + .filter(anno => !anno.hidden) .map(anno => ( ))} diff --git a/src/fields/util.ts b/src/fields/util.ts index 4a62a6a1f..f222e4555 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -4,7 +4,6 @@ import { DocServer } from '../client/DocServer'; import { CollectionViewType } from '../client/documents/DocumentTypes'; import { SerializationHelper } from '../client/util/SerializationHelper'; import { UndoManager } from '../client/util/UndoManager'; -import { CollectionDockingView } from '../client/views/collections/CollectionDockingView'; import { returnZero } from '../Utils'; import CursorField from './CursorField'; import { -- cgit v1.2.3-70-g09d2 From f303131b40fac4909ab2730b369ef3bdb8e00b1d Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 21 Feb 2023 09:53:18 -0500 Subject: fixed explore mode zooming. don't show doc decorations until you move outside of the document, fixed dragging radius button over webbox to still get pointer events. fixed selection text in coments for web boxes.. fixed setting default background color for notes. fixed mode buttons to trigger click behavior before double click behavior. fixed events on nested text boxes that are linkAnchors (like text quotes in sidebar comments), --- src/Utils.ts | 9 +++--- src/client/documents/Documents.ts | 5 ++-- src/client/util/CurrentUserUtils.ts | 7 +++-- src/client/views/DocumentDecorations.tsx | 20 +++++++------ src/client/views/Main.tsx | 5 ++-- src/client/views/MarqueeAnnotator.tsx | 2 +- src/client/views/SidebarAnnos.tsx | 25 ++++++++-------- src/client/views/StyleProvider.tsx | 3 +- .../views/collections/CollectionStackingView.tsx | 8 ++++-- .../views/collections/CollectionTreeView.tsx | 5 +++- src/client/views/collections/TreeView.tsx | 33 +++++++++++++++++----- .../collectionFreeForm/CollectionFreeFormView.tsx | 6 +++- src/client/views/nodes/DocumentView.tsx | 6 ++-- src/client/views/nodes/ImageBox.tsx | 4 +-- src/client/views/nodes/WebBox.tsx | 11 ++++++-- src/client/views/nodes/button/FontIconBox.tsx | 15 +++------- .../views/nodes/formattedText/DashFieldView.tsx | 22 +++++++++++++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 22 ++++++--------- .../views/nodes/formattedText/RichTextMenu.tsx | 21 ++++++++------ src/client/views/topbar/TopBar.tsx | 2 +- 20 files changed, 145 insertions(+), 86 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 9d3b9eb2b..22c8cb902 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -686,8 +686,9 @@ export function DashColor(color: string) { try { return color ? Color(color.toLowerCase()) : Color('transparent'); } catch (e) { - console.log('COLOR error:', e); - return Color('red'); + if (color.includes('gradient')) console.log("using color 'white' in place of :" + color); + else console.log('COLOR error:', e); + return Color('white'); } } @@ -816,7 +817,7 @@ export function setupMoveUpEvents( (target as any)._noClick = clickEvent(e, (target as any)._doubleTap); } document.removeEventListener('pointermove', _moveEvent); - document.removeEventListener('pointerup', _upEvent); + document.removeEventListener('pointerup', _upEvent, true); }; const _clickEvent = (e: MouseEvent): void => { if ((target as any)._noClick) e.stopPropagation(); @@ -827,6 +828,6 @@ export function setupMoveUpEvents( e.preventDefault(); } document.addEventListener('pointermove', _moveEvent); - document.addEventListener('pointerup', _upEvent); + document.addEventListener('pointerup', _upEvent, true); document.addEventListener('click', _clickEvent, true); } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 3faa6e11d..debb11066 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -224,6 +224,7 @@ export class DocumentOptions { contextMenuScripts?: List; contextMenuLabels?: List; contextMenuIcons?: List; + allowClickBeforeDoubleClick?: boolean; // whether a click function can fire before the timeout for a double click has expired dontUndo?: boolean; // whether button clicks should be undoable (this is set to true for Undo/Redo/and sidebar buttons that open the siebar panel) description?: string; // added for links layout?: string | Doc; // default layout string for a document @@ -583,7 +584,7 @@ export namespace Docs { DocumentType.FONTICON, { layout: { view: FontIconBox, dataField: defaultDataKey }, - options: { hideLinkButton: true, _width: 40, _height: 40, borderRounding: '100%', links: '@links(self)' }, + options: { allowClickBeforeDoubleClick: true, hideLinkButton: true, _width: 40, _height: 40, borderRounding: '100%', links: '@links(self)' }, }, ], [ @@ -1808,7 +1809,7 @@ export namespace DocUtils { _yMargin: noMargins ? 0 : undefined, annotationOn, docMaxAutoHeight: maxHeight, - backgroundColor: backgroundColor, + backgroundColor, _width: width || 200, _height: 35, x: x, diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index f678c8936..3d95cb947 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -612,6 +612,7 @@ export class CurrentUserUtils { btnList: new List(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) }, { title: "Size", toolTip: "Font size", width: 75, btnType: ButtonType.NumberButton, ignoreClick: true, scripts: {script: '{ return setFontSize(value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions }, { title: "Color", toolTip: "Font color", btnType: ButtonType.ColorButton, icon: "font", ignoreClick: true, scripts: {script: '{ return setFontColor(value, _readOnly_);}'}}, + { title: "Highlight",toolTip:"Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", ignoreClick: true, scripts: {script: '{ return setFontHighlight(value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} }, { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", scripts: {onClick: '{ return toggleBold(_readOnly_); }'} }, { title: "Italic", toolTip: "Italic (Ctrl+I)", btnType: ButtonType.ToggleButton, icon: "italic", scripts: {onClick: '{ return toggleItalic(_readOnly_);}'} }, { title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", scripts: {onClick: '{ return toggleUnderline(_readOnly_);}'} }, @@ -635,9 +636,9 @@ export class CurrentUserUtils { { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", scripts: {onClick:'{ return setActiveTool("write", false, _readOnly_);}'} }, { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", scripts: {onClick:'{ return setActiveTool("eraser", false, _readOnly_);}' }}, // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", scripts:{onClick: 'setActiveTool("highlighter")'} }, - { title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", scripts: {onClick:`{ return setActiveTool("${GestureUtils.Gestures.Circle}", false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool("${GestureUtils.Gestures.Circle}", true, _readOnly_);}`} }, - { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", scripts: {onClick:`{ return setActiveTool("${GestureUtils.Gestures.Rectangle}", false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool("${GestureUtils.Gestures.Rectangle}", true, _readOnly_);}`} }, - { title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", scripts: {onClick:`{ return setActiveTool("${GestureUtils.Gestures.Line}", false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool("${GestureUtils.Gestures.Line}", true, _readOnly_);}`} }, + { title: "Circle", toolTip: "Circle (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "circle", scripts: {onClick:`{ return setActiveTool("${GestureUtils.Gestures.Circle}", false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool("${GestureUtils.Gestures.Circle}", true, _readOnly_);}`} }, + { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", scripts: {onClick:`{ return setActiveTool("${GestureUtils.Gestures.Rectangle}", false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool("${GestureUtils.Gestures.Rectangle}", true, _readOnly_);}`} }, + { title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", scripts: {onClick:`{ return setActiveTool("${GestureUtils.Gestures.Line}", false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool("${GestureUtils.Gestures.Line}", true, _readOnly_);}`} }, { title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle", scripts: {onClick:'{ return setIsInkMask(_readOnly_);}'} }, { title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, icon: "fill-drip",ignoreClick: true, scripts: {script: '{ return setFillColor(value, _readOnly_);}'} }, { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, ignoreClick: true, scripts: {script: '{ return setStrokeWidth(value, _readOnly_);}'}, numBtnType: NumButtonType.Slider, numBtnMin: 1}, diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 41f4a17fb..21f63ada4 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -2,7 +2,7 @@ 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'; @@ -182,7 +182,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P dragData.removeDocument = dragDocView.props.removeDocument; dragData.isDocDecorationMove = true; dragData.canEmbed = dragTitle; - this._hidden = this.Interacting = true; + this._hidden = true; DragManager.StartDocumentDrag( SelectionManager.Views().map(dv => dv.ContentDiv!), dragData, @@ -191,7 +191,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P { dragComplete: action(e => { dragData.canEmbed && SelectionManager.DeselectAll(); - this._hidden = this.Interacting = false; + this._hidden = false; }), hideSource: true, } @@ -293,7 +293,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P */ @action onRadiusDown = (e: React.PointerEvent): void => { - this._isRounding = true; + this._isRounding = DocumentDecorations.Instance.Interacting = true; this._resizeUndo = UndoManager.StartBatch('DocDecs set radius'); // Call util move event function setupMoveUpEvents( @@ -316,10 +316,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P return false; }, // moveEvent action(e => { - this._isRounding = false; + DocumentDecorations.Instance.Interacting = this._isRounding = false; this._resizeUndo?.end(); }), // upEvent - e => {} // clickEvent + e => {}, // clickEvent, + true ); }; @@ -710,11 +711,14 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P return this._rotCenter; } + @observable _showNothing = true; + render() { const { b, r, x, y } = this.Bounds; const bounds = { b, r, x, y }; - const seldocview = SelectionManager.Views().slice(-1)[0]; + const seldocview = SelectionManager.Views().lastElement(); if (SnappingManager.GetIsDragging() || bounds.r - bounds.x < 1 || bounds.x === Number.MAX_VALUE || !seldocview || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) { + setTimeout(action(() => (this._showNothing = true))); return null; } // hide the decorations if the parent chooses to hide it or if the document itself hides it @@ -812,7 +816,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
); return ( -
+
(this._showNothing = false))}>
{ MainView.Live = window.location.search.includes('live'); - ReactDOM.createRoot(document.getElementById('root')!).render(); + const root = ReactDOM.createRoot(document.getElementById('root')!); + root.render(); window.location.search.includes('safe') && CollectionView.SetSafeMode(true); const info = await CurrentUserUtils.loadCurrentUser(); if (info.email === 'guest') DocServer.Control.makeReadOnly(); @@ -47,6 +48,6 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0 }; // bcz: not sure new LinkManager(); new TrackMovements(); new ReplayMovements(); - ReactDOM.createRoot(document.getElementById('root')!).render(); + root.render(); }, 0); })(); diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 5ab91dd70..3bdf65d01 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -49,7 +49,7 @@ export class MarqueeAnnotator extends React.Component { super(props); AnchorMenu.Instance.OnCrop = (e: PointerEvent) => this.props.anchorMenuCrop?.(this.highlight('', true), true); - AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true)); + AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true, undefined, true)); AnchorMenu.Instance.OnAudio = unimplementedFunction; AnchorMenu.Instance.Highlight = this.highlight; AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap, addAsAnnotation?: boolean) => this.highlight('rgba(173, 216, 230, 0.75)', true, savedAnnotations, true); diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 6d06bbbf6..b9af28413 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -88,6 +88,7 @@ export class SidebarAnnos extends React.Component { }; }); + if (!anchor.text) Doc.GetProto(anchor).text = '-selection-'; const textLines: any = [ { type: 'paragraph', @@ -121,16 +122,18 @@ export class SidebarAnnos extends React.Component { content: taggedContent, }; if (taggedContent.length) textLines.push(metadatatext); - Doc.GetProto(target).text = new RichTextField( - JSON.stringify({ - doc: { - type: 'doc', - content: textLines, - }, - selection: { type: 'text', anchor: 4, head: 4 }, // set selection to middle paragraph - }), - '' - ); + if (textLines.length) { + Doc.GetProto(target).text = new RichTextField( + JSON.stringify({ + doc: { + type: 'doc', + content: textLines, + }, + selection: { type: 'text', anchor: 4, head: 4 }, // set selection to middle paragraph + }), + '' + ); + } this.addDocument(target); setTimeout(() => this._stackRef.current?.focusDocument(target, {})); return target; @@ -233,7 +236,7 @@ export class SidebarAnnos extends React.Component { isAnnotationOverlay={false} select={emptyFunction} NativeDimScaling={returnOne} - childShowTitle={this.showTitle} + //childShowTitle={this.showTitle} childDocumentsActive={this.props.isContentActive} whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} childHideDecorationTitle={returnTrue} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 3cb920ba0..817baeae6 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -19,6 +19,7 @@ import { SliderBox } from './nodes/SliderBox'; import './StyleProvider.scss'; import React = require('react'); import { Shadows } from 'browndash-components'; +import { SelectionManager } from '../util/SelectionManager'; export enum StyleProp { TreeViewIcon = 'treeViewIcon', @@ -116,7 +117,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt dv.rootDoc === doc) ? 'black' : highlightColor, highlightIndex, highlightStroke: doc.type === DocumentType.INK }; } } return undefined; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 2f495d55c..6314b4529 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -129,6 +129,7 @@ export class CollectionStackingView extends CollectionSubView (this._renderCount = Math.min(docs.length, this._renderCount + 5)))); return docs.map((d, i) => { const height = () => this.getDocHeight(d); const width = () => this.getDocWidth(d); @@ -139,7 +140,7 @@ export class CollectionStackingView extends CollectionSubView - {this.getDisplayDoc(d, width)} + {this.getDisplayDoc(d, width, i)}
); }); @@ -297,12 +298,13 @@ export class CollectionStackingView extends CollectionSubView (this.props.isSelected() || this.props.isContentActive() ? true : this.props.isSelected() === false || this.props.isContentActive() === false ? false : undefined); + @observable _renderCount = 5; isChildContentActive = () => this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined; isChildButtonContentActive = () => (this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined); // 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) { + getDisplayDoc(doc: Doc, width: () => number, count: number) { const dataDoc = !doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS ? undefined : this.props.DataDoc; const height = () => this.getDocHeight(doc); @@ -310,7 +312,7 @@ export class CollectionStackingView extends CollectionSubView this.getDocTransform(doc, dref); this._docXfs.push({ stackedDocTransform, width, height }); //DocumentView is how the node will be rendered - return ( + return count > this._renderCount ? null : ( (dref = r || undefined)} Document={doc} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 1a265af4a..456f2a13d 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -259,11 +259,13 @@ export class CollectionTreeView extends CollectionSubView ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); }; headerFields = () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields); + @observable _renderCount = 1; @computed get treeViewElements() { TraceMobx(); const dropAction = StrCast(this.doc.childDropAction) as dropActionType; const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before); const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument?.(d, target, addDoc) || false; + if (this.treeChildren.length < this._renderCount) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20)))); return TreeView.GetChildElements( this.treeChildren, this, @@ -296,7 +298,8 @@ export class CollectionTreeView extends CollectionSubView { private _header: React.RefObject = React.createRef(); private _tref = React.createRef(); @observable _docRef: Opt; - private _selDisposer: Opt; + private _disposers: { [name: string]: IReactionDisposer } = {}; private _editTitleScript: (() => ScriptField) | undefined; private _openScript: (() => ScriptField) | undefined; private _treedropDisposer?: DragManager.DragDropDisposer; @@ -212,14 +213,14 @@ export class TreeView extends React.Component { }; @action setEditTitle = (docView?: DocumentView) => { - this._selDisposer?.(); + this._disposers.selection?.(); if (!docView) { this._editTitle = false; } else if (docView.isSelected()) { const doc = docView.Document; SelectionManager.SelectSchemaViewDoc(doc); this._editTitle = true; - this._selDisposer = reaction( + this._disposers.selection = reaction( () => SelectionManager.SelectedSchemaDoc(), seldoc => seldoc !== doc && this.setEditTitle(undefined) ); @@ -259,7 +260,8 @@ export class TreeView extends React.Component { }; componentWillUnmount() { - this._selDisposer?.(); + this._renderTimer && clearTimeout(this._renderTimer); + Object.values(this._disposers).forEach(disposer => disposer?.()); this._treeEle && this.props.unobserveHeight(this._treeEle); document.removeEventListener('pointermove', this.onDragMove, true); document.removeEventListener('pointermove', this.onDragUp, true); @@ -268,6 +270,10 @@ export class TreeView extends React.Component { } componentDidUpdate() { + this._disposers.opening = reaction( + () => this.treeViewOpen, + open => !open && (this._renderCount = 20) + ); this.props.hierarchyIndex !== undefined && this.props.AddToMap?.(this.doc, this.props.hierarchyIndex); } @@ -512,6 +518,8 @@ export class TreeView extends React.Component { return rows; } + _renderTimer: any; + @observable _renderCount = 1; @computed get renderContent() { TraceMobx(); const expandKey = this.treeViewExpandedView; @@ -543,6 +551,14 @@ export class TreeView extends React.Component { const docs = expandKey === 'aliases' ? this.childAliases : expandKey === 'links' ? this.childLinks : expandKey === 'annotations' ? this.childAnnos : this.childDocs; let downX = 0, downY = 0; + if (docs?.length && this._renderCount < docs?.length) { + this._renderTimer && clearTimeout(this._renderTimer); + this._renderTimer = setTimeout( + action(() => { + this._renderCount = Math.min(docs!.length, this._renderCount + 20); + }) + ); + } return ( <> {!docs?.length || this.props.AddToMap /* hack to identify pres box trees */ ? null : ( @@ -599,7 +615,8 @@ export class TreeView extends React.Component { // TODO: [AL] add these this.props.AddToMap, this.props.RemFromMap, - this.props.hierarchyIndex + this.props.hierarchyIndex, + this._renderCount )} @@ -651,7 +668,7 @@ export class TreeView extends React.Component { return (
{ // TODO: [AL] add these AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[], RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[], - hierarchyIndex?: number[] + hierarchyIndex?: number[], + renderCount?: number ) { const viewSpecScript = Cast(containerCollection.viewSpecScript, ScriptField); if (viewSpecScript) { @@ -1144,6 +1162,7 @@ export class TreeView extends React.Component { return docs .filter(child => child instanceof Doc) .map((child, i) => { + if (renderCount && i > renderCount) return null; const pair = Doc.GetLayoutDataDocPair(containerCollection, dataDoc, child); if (!pair.layout || pair.data instanceof Promise) { return null; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d6e95f97f..4d6e0dff2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -53,6 +53,7 @@ import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCurso import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; import React = require('react'); +import { DocumentDecorations } from '../../DocumentDecorations'; export type collectionFreeformViewProps = { annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) @@ -1305,7 +1306,9 @@ export class CollectionFreeFormView extends CollectionSubView { const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); const pointerEvents = - this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.()); + this.props.isContentActive() === false || DocumentDecorations.Instance.Interacting + ? 'none' + : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.()); return pointerEvents; }; getChildDocView(entry: PoolData) { @@ -2287,6 +2290,7 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY SelectionManager.DeselectAll(); dv.props.focus(dv.props.Document, { willPanZoom: true, + zoomScale: 0.8, afterFocus: async didMove => { if (!didMove) { const selfFfview = dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 36c0240f1..3d89566ee 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -664,7 +664,7 @@ export class DocumentViewInternal extends DocComponent (this.props.Document.dontUndo ? func() : UndoManager.RunInBatch(func, 'on click')); - if (this.onDoubleClickHandler) { + if (this.onDoubleClickHandler && !this.props.Document.allowClickBeforeDoubleClick) { runInAction(() => (this._pendingDoubleClick = true)); this._timeout = setTimeout(() => { this._timeout = undefined; @@ -780,7 +780,9 @@ export class DocumentViewInternal extends DocComponent -
+
{fadepath === srcpath ? null : (
this._selectionText; + selectionContent = () => this._selectionContent; @action createTextAnnotation = (sel: Selection, selRange: Range | undefined) => { if (this._mainCont.current && selRange) { @@ -276,6 +280,8 @@ export class WebBox extends ViewBoxAnnotatableComponent e.stopPropagation()} style={{ width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']) || `100%` : '100%' }}> {this.urlContent} @@ -1014,7 +1019,7 @@ export class WebBox extends ViewBoxAnnotatableComponent diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index 9d67283a0..b352f3790 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -136,7 +136,7 @@ export class FontIconBox extends DocComponent() { const setValue = (value: number) => UndoManager.RunInBatch(() => numScript?.script.run({ value, _readOnly_: false }), 'set num value'); // Script for checking the outcome of the toggle - const checkResult: number = numScript?.script.run({ value: 0, _readOnly_: true }).result || 0; + const checkResult = Number(numScript?.script.run({ value: 0, _readOnly_: true }).result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3)); const label = !FontIconBox.GetShowLabels() ? null :
{this.label}
; @@ -150,7 +150,6 @@ export class FontIconBox extends DocComponent() { max={NumCast(this.rootDoc.numBtnMax, 100)} value={checkResult} className={'menu-slider'} - id="slider" onPointerDown={() => (this._batch = UndoManager.StartBatch('presDuration'))} onPointerUp={() => this._batch?.end()} onChange={e => { @@ -642,13 +641,7 @@ ScriptingGlobals.add(function setFontHighlight(color?: string, checkResult?: boo if (checkResult) { return (selected ?? Doc.UserDoc())._fontHighlight; } - if (selected) { - selected._fontColor = color; - if (color) { - editorView?.state && RichTextMenu.Instance.setHighlight(color, editorView, editorView?.dispatch); - } - } - Doc.UserDoc()._fontHighlight = color; + color && RichTextMenu.Instance.setHighlight(color); }); // toggle: Set overlay status of selected document @@ -795,7 +788,7 @@ function setActiveTool(tool: InkTool | GestureUtils.Gestures, keepPrim: boolean, GestureOverlay.Instance.KeepPrimitiveMode = keepPrim; } if (Object.values(GestureUtils.Gestures).includes(tool as any)) { - if (GestureOverlay.Instance.InkShape === tool) { + if (GestureOverlay.Instance.InkShape === tool && !keepPrim) { Doc.ActiveTool = InkTool.None; GestureOverlay.Instance.InkShape = undefined; } else { @@ -804,7 +797,7 @@ function setActiveTool(tool: InkTool | GestureUtils.Gestures, keepPrim: boolean, } } else if (tool) { // pen or eraser - if (Doc.ActiveTool === tool && !GestureOverlay.Instance.InkShape) { + if (Doc.ActiveTool === tool && !GestureOverlay.Instance.InkShape && !keepPrim) { Doc.ActiveTool = InkTool.None; } else { Doc.ActiveTool = tool as any; diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 39005a18b..b33529aeb 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -18,12 +18,18 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { NodeSelection } from 'prosemirror-state'; import { OpenWhere } from '../DocumentView'; +import { FormattedTextBoxComment } from './FormattedTextBoxComment'; export class DashFieldView { dom: HTMLDivElement; // container for label and value root: any; + node: any; + tbox: FormattedTextBox; + unclickable = () => !this.tbox.props.isSelected() && this.node.marks.some((m: any) => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview); constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { + this.node = node; + this.tbox = tbox; this.dom = document.createElement('div'); this.dom.style.width = node.attrs.width; this.dom.style.height = node.attrs.height; @@ -44,7 +50,18 @@ export class DashFieldView { this.root = ReactDOM.createRoot(this.dom); this.root.render( - + ); } destroy() { @@ -68,6 +85,7 @@ interface IDashFieldViewInternal { editable: boolean; node: any; getPos: any; + unclickable: () => boolean; } @observer @@ -125,7 +143,7 @@ export class DashFieldViewInternal extends React.Component(); private _ref: React.RefObject = React.createRef(); @@ -102,7 +101,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this._editorView?.state && RichTextMenu.Instance.setHighlight(color, this._editorView, this._editorView?.dispatch); + this._editorView?.state && RichTextMenu.Instance.setHighlight(color); return undefined; }); AnchorMenu.Instance.onMakeAnchor = () => this.getAnchor(true); @@ -788,7 +786,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (FormattedTextBox._canAnnotate = !FormattedTextBox._canAnnotate), icon: 'expand-arrows-alt' }); uicontrols.push({ description: !this.Document._noSidebar ? 'Hide Sidebar Handle' : 'Show Sidebar Handle', event: () => (this.layoutDoc._noSidebar = !this.layoutDoc._noSidebar), icon: 'expand-arrows-alt' }); uicontrols.push({ description: 'Show Highlights...', noexpand: true, subitems: highlighting, icon: 'hand-point-right' }); !Doc.noviceMode && @@ -1455,7 +1452,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if (!this._editorView?.state.selection.empty && !(this._editorView?.state.selection instanceof NodeSelection) && FormattedTextBox._canAnnotate && !(e.nativeEvent as any).dash) this.setupAnchorMenu(); - if (!this._downEvent) return; - this._downEvent = false; - if (this._editorView?.state.selection.empty && this.props.isContentActive(true) && !(e.nativeEvent as any).dash) { - const editor = this._editorView!; + const editor = this._editorView!; + const state = editor?.state; + if (!state || !editor) return; + if (!state.selection.empty && !(state.selection instanceof NodeSelection)) this.setupAnchorMenu(); + else if (this.props.isContentActive(true)) { const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY }); - !this.props.isSelected(true) && editor.dispatch(editor.state.tr.setSelection(new TextSelection(editor.state.doc.resolve(pcords?.pos || 0)))); + !this.props.isSelected(true) && editor.dispatch(state.tr.setSelection(new TextSelection(state.doc.resolve(pcords?.pos || 0)))); let target = e.target as any; // hrefs are stored on the dataset of the node that wraps the hyerlink while (target && !target.dataset?.targethrefs) target = target.parentElement; FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview === 'true'); - if (pcords && pcords.inside > 0 && this._editorView.state.doc.nodeAt(pcords.inside)?.type === this._editorView.state.schema.nodes.dashDoc) { + if (pcords && pcords.inside > 0 && state.doc.nodeAt(pcords.inside)?.type === state.schema.nodes.dashDoc) { return; } } diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index b70da2e5e..f0caa1f4f 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -54,7 +54,7 @@ export class RichTextMenu extends AntimodeMenu { @observable private _activeFontColor: string = 'black'; @observable private showColorDropdown: boolean = false; - @observable private activeHighlightColor: string = 'transparent'; + @observable private _activeHighlightColor: string = 'transparent'; @observable private showHighlightDropdown: boolean = false; @observable private currentLink: string | undefined = ''; @@ -89,6 +89,9 @@ export class RichTextMenu extends AntimodeMenu { @computed get fontColor() { return this._activeFontColor; } + @computed get fontHighlight() { + return this._activeHighlightColor; + } @computed get fontFamily() { return this._activeFontFamily; } @@ -138,7 +141,7 @@ export class RichTextMenu extends AntimodeMenu { this._activeFontFamily = !activeFamilies.length ? StrCast(this.TextView?.Document.fontFamily, StrCast(Doc.UserDoc().fontFamily, 'Arial')) : activeFamilies.length === 1 ? String(activeFamilies[0]) : 'various'; this._activeFontSize = !activeSizes.length ? StrCast(this.TextView?.Document.fontSize, StrCast(Doc.UserDoc().fontSize, '10px')) : activeSizes[0]; this._activeFontColor = !activeColors.length ? StrCast(this.TextView?.Document.fontColor, StrCast(Doc.UserDoc().fontColor, 'black')) : activeColors.length > 0 ? String(activeColors[0]) : '...'; - this.activeHighlightColor = !activeHighlights.length ? '' : activeHighlights.length > 0 ? String(activeHighlights[0]) : '...'; + this._activeHighlightColor = !activeHighlights.length ? '' : activeHighlights.length > 0 ? String(activeHighlights[0]) : '...'; // update link in current selection this.getTextLinkTargetTitle().then(targetTitle => this.setCurrentLink(targetTitle)); @@ -356,11 +359,13 @@ export class RichTextMenu extends AntimodeMenu { this.updateMenu(this.view, undefined, this.props); }; - setHighlight(color: String, view: EditorView, dispatch: any) { - const highlightMark = view.state.schema.mark(view.state.schema.marks.marker, { highlight: color }); - if (view.state.selection.empty) return false; - view.focus(); - this.setMark(highlightMark, view.state, dispatch, false); + setHighlight(color: string) { + if (this.view) { + const highlightMark = this.view.state.schema.mark(this.view.state.schema.marks.marker, { highlight: color }); + this.setMark(highlightMark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(highlightMark)), true); + this.view.focus(); + } else Doc.UserDoc()._fontHighlight = color; + this.updateMenu(this.view, undefined, this.props); } setColor(color: string) { @@ -563,7 +568,7 @@ export class RichTextMenu extends AntimodeMenu { } @action setActiveHighlight(color: string) { - this.activeHighlightColor = color; + this._activeHighlightColor = color; } @action setCurrentLink(link: string) { diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 7e728306c..f2e9be61d 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -54,7 +54,7 @@ export class TopBar extends React.Component { dash
)} - {Doc.ActiveDashboard && !Doc.noviceMode && ( + {Doc.ActiveDashboard && (
); }; @@ -389,7 +383,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { 1.0, false ); - const highlight = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Highlighting); + const highlight = !this.controlUndo && this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Highlighting); const highlightIndex = highlight?.highlightIndex; const highlightColor = highlight?.highlightIndex ? highlight?.highlightColor : StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent'); // Invisible polygonal line that enables the ink to be selected by the user. diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 895ed9bda..625dc2748 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -606,7 +606,7 @@ export class MainView extends React.Component { @computed get mainDocView() { return ( <> - {this._hideUI ? null : this.headerBarDocView} + {this._hideUI || !this.headerBarDocHeight?.() ? null : this.headerBarDocView} {
{!selectedItem ? null : (
-
{ - this.openPresTransitions = !this.openPresTransitions; - })} - style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}> +
(this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>     Transitions
@@ -1830,12 +1825,7 @@ export class PropertiesView extends React.Component { )} {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : (
-
{ - this.openSlideOptions = !this.openSlideOptions; - })} - style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}> +
(this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>     {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index e2594b6ae..c83f4e689 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -15,6 +15,7 @@ import { RichTextField } from '../../../fields/RichTextField'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, 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'; @@ -40,7 +41,7 @@ import { CollectionLinearView } from './collectionLinear'; import './CollectionMenu.scss'; import { COLLECTION_BORDER_WIDTH } from './CollectionView'; import { TabDocView } from './TabDocView'; -import { GestureUtils } from '../../../pen-gestures/GestureUtils'; +import { CollectionFreeFormView } from './collectionFreeForm'; interface CollectionMenuProps { panelHeight: () => number; @@ -733,7 +734,7 @@ export class CollectionFreeFormViewChrome extends React.Component this.addDoc(doc, relativeTo, before); const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument?.(d, target, addDoc) || false; - if (this.treeChildren.length < this._renderCount) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20)))); + if (this._renderCount < this.treeChildren.length) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20)))); return TreeView.GetChildElements( this.treeChildren, this, diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index d6bc0a4b2..fa648eb44 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -248,7 +248,7 @@ export class TabDocView extends React.Component { return; } const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false); - const pinDoc = Doc.MakeDelegate(anchorDoc ?? doc); + const pinDoc = anchorDoc && anchorDoc !== doc ? anchorDoc : Doc.MakeDelegate(doc); pinDoc.presentationTargetDoc = anchorDoc ?? doc; pinDoc.title = doc.title + ' - Slide'; pinDoc.data = new List(); // the children of the alias' layout are the presentation slide children. the alias' 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 diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4d6e0dff2..e5b4b76a8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -54,6 +54,7 @@ import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; import React = require('react'); import { DocumentDecorations } from '../../DocumentDecorations'; +import { PresEffect } from '../../nodes/trails'; export type collectionFreeformViewProps = { annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) @@ -150,7 +151,7 @@ export class CollectionFreeFormView extends CollectionSubView e.bounds && !e.bounds.z).map(e => e.bounds!), + this._layoutElements.filter(e => e.bounds && e.bounds.width && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10) ); @@ -185,6 +186,32 @@ export class CollectionFreeFormView extends CollectionSubView { + CollectionFreeFormDocumentView.animFields.forEach(val => { + 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); + 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); + findexed?.length <= timecode + 1 && findexed.push(undefined as any); + }); + }); + return newTimer; + } + changeKeyFrame = (back = false) => { const currentFrame = Cast(this.Document._currentFrame, 'number', null); if (currentFrame === undefined) { @@ -192,10 +219,10 @@ export class CollectionFreeFormView extends CollectionSubView this.isCurrent(entry[1].pair.layout)) - .forEach((entry, i) => + .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); elements.push({ ele: this.getChildDocView(entry[1]), - bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica), + bounds: childData.opacity === 0 ? { ...childData, width: 0, height: 0 } : { ...childData, width: childSize.width, height: childSize.height }, inkMask: BoolCast(entry[1].pair.layout.isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1, - }) - ); + }); + }); if (this.props.isAnnotationOverlay && this.props.Document[this.scaleFieldKey]) { // don't zoom out farther than 1-1 if it's a bounded item (image, video, pdf), otherwise don't allow zooming in closer than 1-1 if it's a text sidebar @@ -1988,7 +2018,7 @@ export class CollectionFreeFormView extends CollectionSubView {this.children} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index bc3b17cd9..bd33c4d80 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -397,6 +397,7 @@ export class MarqueeView extends React.Component (d.context = newCollection)); this.hideMarquee(); return newCollection; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index f8ef87fb1..ba510e1dc 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -40,6 +40,8 @@ export class CollectionFreeFormDocumentView extends DocComponent { - CollectionFreeFormDocumentView.animFields.forEach(val => { - 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); - 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); - findexed?.length <= timecode + 1 && findexed.push(undefined as any); - }); - }); - return newTimer; - } - - public static gotoKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], duration = 1000) { - if (timer) clearTimeout(timer); - return DocumentView.SetViewTransition(docs, 'all', duration, undefined, true); - } - public static setupZoom(doc: Doc, targDoc: Doc) { const width = new List(); const height = new List(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3d89566ee..c3b0412de 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -17,7 +17,7 @@ import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from import { AudioField } from '../../../fields/URLField'; import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util'; import { MobileInterface } from '../../../mobile/MobileInterface'; -import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils'; +import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnNone, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils'; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { DocServer } from '../../DocServer'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -252,6 +252,7 @@ export class DocumentViewInternal extends DocComponent StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name); (this.rootDoc._raiseWhenDragged === undefined ? DragManager.GetRaiseWhenDragged() : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc); - if (this._doubleTap && (this.props.Document.type !== DocumentType.FONTICON || this.onDoubleClickHandler)) { + if (this._doubleTap && (![DocumentType.FONTICON, DocumentType.PRES].includes(this.props.Document.type as any) || this.onDoubleClickHandler)) { // && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (this._timeout) { clearTimeout(this._timeout); @@ -718,6 +719,7 @@ export class DocumentViewInternal extends DocComponent 0))) { // if this is part of a template, let the event go up to the tempalte root unless right/ctrl clicking if ( @@ -777,11 +779,10 @@ export class DocumentViewInternal extends DocComponent() { className="list-item" key={`${value}`} style={{ - backgroundColor: value === checkResult ? Colors.LIGHT_BLUE : undefined, + backgroundColor: value.toString() === checkResult ? Colors.LIGHT_BLUE : undefined, }} onClick={() => setValue(value)}> {value} diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index e07517113..929bf1230 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,10 +1,10 @@ import React = require('react'); import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; -import { action, computed, IReactionDisposer, observable, ObservableSet, observe, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; -import { AnimationSym, Doc, DocListCast, FieldResult, HighlightSym, Opt, StrListCast } from '../../../../fields/Doc'; +import { AnimationSym, Doc, DocListCast, FieldResult, Opt, StrListCast } from '../../../../fields/Doc'; import { Copy, Id } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; @@ -14,7 +14,7 @@ import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Ty import { AudioField } from '../../../../fields/URLField'; import { emptyFunction, emptyPath, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; -import { Docs, DocumentOptions } from '../../../documents/Documents'; +import { Docs } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { DocumentManager } from '../../../util/DocumentManager'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; @@ -23,19 +23,17 @@ import { SettingsManager } from '../../../util/SettingsManager'; import { undoBatch, UndoManager } from '../../../util/UndoManager'; 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 { ViewBoxBaseComponent } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; import { LightboxView } from '../../LightboxView'; -import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentView'; import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; -import { CollectionStackedTimeline } from '../../collections/CollectionStackedTimeline'; -import { PresElementBox } from './PresElementBox'; const { Howl } = require('howler'); export interface PinProps { @@ -296,7 +294,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (context) { const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.ComponentView as CollectionFreeFormView; if (ffview?.childDocs) { - this._keyTimer = CollectionFreeFormDocumentView.gotoKeyframe(this._keyTimer, ffview.childDocs.slice(), transTime); + this._keyTimer = CollectionFreeFormView.gotoKeyframe(this._keyTimer, ffview.childDocs, transTime); context._currentFrame = NumCast(activeFrame); } } @@ -598,7 +596,7 @@ export class PresBox extends ViewBoxBaseComponent() { tagDoc.opacity = 1; } } - const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex); + const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex) ?? itemIndexes.slice().reverse().lastElement(); if (curDoc.presHideBefore && index === hidingIndBef) { if (index > this.itemIndex) { tagDoc.opacity = 0; @@ -606,10 +604,11 @@ export class PresBox extends ViewBoxBaseComponent() { tagDoc.opacity = 1; } } - const hidingIndAft = itemIndexes - .slice() - .reverse() - .find(item => item < this.itemIndex); + const hidingIndAft = + itemIndexes + .slice() + .reverse() + .find(item => item <= this.itemIndex) ?? itemIndexes.lastElement(); if (curDoc.presHideAfter && index === hidingIndAft) { if (index < this.itemIndex) { tagDoc.opacity = 0; @@ -875,7 +874,12 @@ export class PresBox extends ViewBoxBaseComponent() { @action selectElement = async (doc: Doc, noNav = false) => { CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => DocumentManager.Instance.getDocumentView(clip)?.ComponentView?.Pause?.()); - !noNav && this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem); + if (noNav) { + const index = this.childDocs.indexOf(doc); + if (index >= 0 && index < this.childDocs.length) { + this.rootDoc._itemIndex = index; + } + } else this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem); this.updateCurrentPresentation(DocCast(doc.context)); }; @@ -911,19 +915,19 @@ export class PresBox extends ViewBoxBaseComponent() { //regular click @action - regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, selectPres = true, noNav = false) => { + regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, noNav: boolean, selectPres = true) => { this.clearSelectedArray(); this.addToSelectedArray(doc); this._eleArray.splice(0, this._eleArray.length, ref); this._dragArray.splice(0, this._dragArray.length, drag); - focus && this.selectElement(doc, noNav); + this.selectElement(doc, noNav); selectPres && this.selectPres(); }; - modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, cmdClick: boolean, shiftClick: boolean, noNav: boolean = false) => { + modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, noNav: boolean, cmdClick: boolean, shiftClick: boolean) => { if (cmdClick) this.multiSelect(doc, ref, drag); else if (shiftClick) this.shiftSelect(doc, ref, drag); - else this.regularSelect(doc, ref, drag, focus, noNav); + else this.regularSelect(doc, ref, drag, noNav); }; static keyEventsWrapper = (e: KeyboardEvent) => PresBox.Instance?.keyEvents(e); diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index f265c1315..40535c8cb 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -139,7 +139,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { onClick={e => { e.stopPropagation(); e.preventDefault(); - this.presBoxView?.modifierSelect(doc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); + this.presBoxView?.modifierSelect(doc, this._itemRef.current!, this._dragRef.current!, e.shiftKey || e.ctrlKey || e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); this.presExpandDocumentClick(); }}>
{`${ind + 1}.`}
@@ -177,22 +177,14 @@ export class PresElementBox extends ViewBoxBaseComponent() { const element = e.target as any; e.stopPropagation(); e.preventDefault(); - if (element && !(e.ctrlKey || e.metaKey)) { - if (this.selectedArray?.has(this.rootDoc)) { - this.selectedArray.size === 1 && this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false); - setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction); - } else { - setupMoveUpEvents( - this, - e, - (e: PointerEvent) => { - this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false); - return this.startDrag(e); - }, - emptyFunction, - emptyFunction - ); - } + if (element && !(e.ctrlKey || e.metaKey || e.button === 2)) { + this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true, false); + setupMoveUpEvents(this, e, this.startDrag, emptyFunction, e => { + e.stopPropagation(); + e.preventDefault(); + this.presBoxView?.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, e.shiftKey || e.ctrlKey || e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); + this.presBoxView?.activeItem && this.showRecording(this.presBoxView?.activeItem); + }); } }; @@ -314,50 +306,14 @@ export class PresElementBox extends ViewBoxBaseComponent() { /** * Method called for updating the view of the currently selected document * - * @param targetDoc + * @param presTargetDoc * @param activeItem */ @undoBatch @action - updateCapturedViewContents = (targetDoc: Doc, activeItem: Doc) => { - switch (targetDoc.type) { - case DocumentType.PDF: - case DocumentType.WEB: - case DocumentType.RTF: - const scroll = targetDoc._scrollTop; - activeItem.presPinViewScroll = scroll; - if (targetDoc.type === DocumentType.RTF) { - activeItem.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof RichTextField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as RichTextField)[Copy]() : targetDoc.text; - } - break; - case DocumentType.INK: - activeItem.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof InkField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as InkField)[Copy]() : targetDoc.data; - break; - case DocumentType.VID: - case DocumentType.AUDIO: - activeItem.presStartTime = targetDoc._currentTimecode; - break; - case DocumentType.COMPARISON: - const clipWidth = targetDoc._clipWidth; - activeItem.presPinClipWidth = clipWidth; - break; - case DocumentType.COL: - activeItem.presPinLayoutData = new List(DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]).map(d => JSON.stringify({ id: d[Id], x: NumCast(d.x), y: NumCast(d.y), w: NumCast(d._width), h: NumCast(d._height) }))); - default: - const bestView = DocumentManager.Instance.getFirstDocumentView(targetDoc); - if (activeItem.presPinViewBounds && bestView) { - const bounds = MarqueeView.CurViewBounds(targetDoc, bestView.props.PanelWidth(), bestView.props.PanelHeight()); - activeItem.presPinView = true; - activeItem.presPinViewScale = NumCast(targetDoc._viewScale, 1); - activeItem.presPinViewX = bounds.left + bounds.width / 2; - activeItem.presPinViewY = bounds.top + bounds.height / 2; - activeItem.presPinViewBounds = new List([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); - } else { - activeItem.presPinViewX = targetDoc._panX; - activeItem.presPinViewY = targetDoc._panY; - activeItem.presPinViewScale = targetDoc._viewScale; - } - } + updateCapturedViewContents = (presTargetDoc: Doc, activeItem: Doc) => { + const target = DocCast(presTargetDoc.annotationOn) ?? presTargetDoc; + PresBox.pinDocView(activeItem, { pinDocContent: true, pinData: PresBox.pinDataTypes(target) }, target); }; @computed get recordingIsInOverlay() { @@ -465,24 +421,26 @@ export class PresElementBox extends ViewBoxBaseComponent() { const activeItem: Doc = this.rootDoc; const items: JSX.Element[] = []; - if (activeItem.presPinLayout) { - items.push( - Update captured doc layout
}> -
this.updateCapturedContainerLayout(targetDoc, activeItem)} style={{ fontWeight: 700, display: 'flex' }}> - L -
- - ); - } - if (activeItem.presPinData || activeItem.presPinView) { - items.push( - Update captured doc content
}> -
this.updateCapturedViewContents(targetDoc, activeItem)} style={{ fontWeight: 700, display: 'flex' }}> - C -
- - ); - } + items.push( + Update captured doc layout
}> +
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedContainerLayout(targetDoc, activeItem), true)} + style={{ opacity: activeItem.presPinLayout ? 1 : 0.5, fontWeight: 700, display: 'flex' }}> + L +
+ + ); + items.push( + Update captured doc content
}> +
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedViewContents(targetDoc, activeItem))} + style={{ opacity: activeItem.presPinData || activeItem.presPinView ? 1 : 0.5, fontWeight: 700, display: 'flex' }}> + C +
+ + ); if (!Doc.noviceMode) { items.push( {this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}
}> @@ -557,15 +515,9 @@ export class PresElementBox extends ViewBoxBaseComponent() { paddingTop: NumCast(this.layoutDoc._yPadding, this.props.yPadding), paddingBottom: NumCast(this.layoutDoc._yPadding, this.props.yPadding), }} - onClick={e => { - e.stopPropagation(); - e.preventDefault(); - this.presBoxView?.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); - this.showRecording(activeItem); - }} onDoubleClick={action(e => { this.toggleProperties(); - this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true); + this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false); })} onPointerOver={this.onPointerOver} onPointerLeave={this.onPointerLeave} @@ -599,7 +551,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { onPointerDown={e => { e.stopPropagation(); if (this._itemRef.current && this._dragRef.current) { - this.presBoxView?.modifierSelect(activeItem, this._itemRef.current, this._dragRef.current, false, false, false, true); + this.presBoxView?.modifierSelect(activeItem, this._itemRef.current, this._dragRef.current, true, false, false); } }} onClick={e => e.stopPropagation()}>{`${this.indexInPres + 1}. `}
diff --git a/src/fields/util.ts b/src/fields/util.ts index 3a7484cfd..6024705ec 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -1,3 +1,4 @@ +import { forEach } from 'lodash'; import { $mobx, action, observable, runInAction, trace } from 'mobx'; import { computedFn } from 'mobx-utils'; import { DocServer } from '../client/DocServer'; -- cgit v1.2.3-70-g09d2 From 096371e683b3f91edfadb2aaf9f8da3309b86014 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 9 Mar 2023 21:39:21 -0500 Subject: added reordering of progressivized docs --- src/client/documents/Documents.ts | 1 + src/client/util/CurrentUserUtils.ts | 2 +- .../views/collections/CollectionTreeView.tsx | 4 +-- src/client/views/collections/CollectionView.tsx | 4 +-- src/client/views/collections/TreeView.tsx | 12 ++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 41 ++++++++++++---------- 7 files changed, 37 insertions(+), 29 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a7378c431..6296b0df4 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -335,6 +335,7 @@ export class DocumentOptions { strokeWidth?: number; freezeChildren?: string; // whether children are now allowed to be added and or removed from a collection treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view + treeViewHideUnrendered?: boolean; // tells tree view not to display documents that have an 'unrendered' tag unless they also have a treeViewFieldKey tag (presBox) treeViewHideHeaderIfTemplate?: boolean; // whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox) treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items. diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index a7b2c3d04..2b0a2cdac 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -269,7 +269,7 @@ export class CurrentUserUtils { {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, _isLinkButton: true }}, {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, // {key: "DataViz", creator: opts => Docs.Create.DataVizDocument(opts), opts: { _width: 300, _height: 300 }}, - {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true,}}, + {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, treeViewHideUnrendered: true}}, {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _viewType: CollectionViewType.Stacking, targetDropAction: "alias" as any, treeViewHideTitle: true, _fitWidth:true, _chromeHidden: true, boxShadow: "0 0" }}, {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _fitWidth: true, _backgroundGridShow: true, }}, {key: "Slide", creator: opts => Docs.Create.TreeDocument([], opts), opts: { _width: 300, _height: 200, _viewType: CollectionViewType.Tree, diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 330e116d1..553967b95 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -38,8 +38,8 @@ export type collectionTreeViewProps = { onCheckedClick?: () => ScriptField; onChildClick?: () => ScriptField; // TODO: [AL] add these fields - AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[]; - RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[]; + AddToMap?: (treeViewDoc: Doc, index: number[]) => void; + RemFromMap?: (treeViewDoc: Doc, index: number[]) => void; hierarchyIndex?: number[]; }; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 316f1e4e9..48e5748a0 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -64,8 +64,8 @@ interface CollectionViewProps_ extends FieldViewProps { childClickScript?: ScriptField; childDoubleClickScript?: ScriptField; //TODO: [AL] add these fields - AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[]; - RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[]; + AddToMap?: (treeViewDoc: Doc, index: number[]) => void; + RemFromMap?: (treeViewDoc: Doc, index: number[]) => void; hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views) } export interface CollectionViewProps extends React.PropsWithChildren {} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 0d2968ba1..c8dc68eae 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -66,8 +66,8 @@ export interface TreeViewProps { skipFields?: string[]; firstLevel: boolean; // TODO: [AL] add these - AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[]; - RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[]; + AddToMap?: (treeViewDoc: Doc, index: number[]) => void; + RemFromMap?: (treeViewDoc: Doc, index: number[]) => void; hierarchyIndex?: number[]; } @@ -1028,7 +1028,9 @@ export class TreeView extends React.Component { // renders the text version of a document as the header. This is used in the file system mode and in other vanilla tree views. @computed get renderTitleAsHeader() { - return ( + return this.props.treeView.Document.treeViewHideUnrendered && this.doc.unrendered && !this.doc.treeViewFieldKey ? ( +
+ ) : ( <> {this.renderBullet} {this.renderTitle} @@ -1146,8 +1148,8 @@ export class TreeView extends React.Component { unobserveHeight: (ref: any) => void, contextMenuItems: { script: ScriptField; filter: ScriptField; label: string; icon: string }[], // TODO: [AL] add these - AddToMap?: (treeViewDoc: Doc, index: number[]) => Doc[], - RemFromMap?: (treeViewDoc: Doc, index: number[]) => Doc[], + AddToMap?: (treeViewDoc: Doc, index: number[]) => void, + RemFromMap?: (treeViewDoc: Doc, index: number[]) => void, hierarchyIndex?: number[], renderCount?: number ) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index b92a8ec4d..87177cd74 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -519,7 +519,7 @@ export class CollectionFreeFormView extends CollectionSubView() { this.activeItem.presIndexed = presIndexed + 1; } return true; - } else { - console.log(this.activeItem.presIndexed); } } }; @@ -359,8 +358,6 @@ export class PresBox extends ViewBoxBaseComponent() { Doc.UnBrushAllDocs(); if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) { DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia); } @@ -368,8 +365,8 @@ export class PresBox extends ViewBoxBaseComponent() { this.stopTempMedia(from.presentationTargetDoc); } // If next slide is audio / video 'Play automatically' then the next slide should be played - if (this.layoutDoc.presStatus !== PresStatus.Edit && (targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && activeItem.mediaStart === 'auto') { - this.startTempMedia(targetDoc, activeItem); + if (this.layoutDoc.presStatus !== PresStatus.Edit && (this.targetDoc.type === DocumentType.AUDIO || this.targetDoc.type === DocumentType.VID) && this.activeItem.mediaStart === 'auto') { + this.startTempMedia(this.targetDoc, this.activeItem); } if (!group) this.clearSelectedArray(); this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array @@ -755,17 +752,18 @@ export class PresBox extends ViewBoxBaseComponent() { const curDoc = Cast(doc, Doc, null); const tagDoc = PresBox.targetRenderedDoc(curDoc); const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc); + let opacity: Opt = index === this.itemIndex ? 1 : undefined; if (curDoc.presHide) { if (index !== this.itemIndex) { - tagDoc.opacity = 1; + opacity = 1; } } const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex) ?? itemIndexes.slice().reverse().lastElement(); if (curDoc.presHideBefore && index === hidingIndBef) { if (index > this.itemIndex) { - tagDoc.opacity = 0; + opacity = 0; } else if (index === this.itemIndex || !curDoc.presHideAfter) { - tagDoc.opacity = 1; + opacity = 1; setTimeout(() => (tagDoc._dataTransition = undefined), 1000); } } @@ -776,17 +774,18 @@ export class PresBox extends ViewBoxBaseComponent() { .find(item => item <= this.itemIndex) ?? itemIndexes.lastElement(); if (curDoc.presHideAfter && index === hidingIndAft) { if (index < this.itemIndex) { - tagDoc.opacity = 0; + opacity = 0; } else if (index === this.itemIndex || !curDoc.presHideBefore) { - tagDoc.opacity = 1; + opacity = 1; } } const hidingInd = itemIndexes.find(item => item === this.itemIndex); if (curDoc.presHide && index === hidingInd) { if (index === this.itemIndex) { - tagDoc.opacity = 0; + opacity = 0; } } + opacity !== undefined && (tagDoc.opacity = opacity); }); }; @@ -882,7 +881,6 @@ export class PresBox extends ViewBoxBaseComponent() { if (doc.presHideBefore && index > startIndex) tagDoc.opacity = 0; if (doc.presHideAfter && index < startIndex) tagDoc.opacity = 0; if (doc.presIndexed !== undefined && index >= startIndex) { - const type = DocCast(tagDoc.annotationOn)?.type ?? tagDoc.type; const startInd = NumCast(doc.presIndexedStart); this.progressivizedItems(doc) ?.slice(startInd) @@ -1552,6 +1550,13 @@ export class PresBox extends ViewBoxBaseComponent() { const tagDoc = PresBox.targetRenderedDoc(this.activeItem); const type = DocCast(tagDoc?.annotationOn)?.type ?? tagDoc.type; activeItem.presIndexedStart = type === DocumentType.COL ? 1 : 0; + // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized. + // to avoid creating a new slide to correspond to each of the target's data list, we simply reference the target's data list. + let dataField = Doc.LayoutFieldKey(tagDoc); + if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '-annotations'; + + if (DocCast(activeItem.presentationTargetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc.annotationOn["${dataField}"]`); + else activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc["${dataField}"]`); }} checked={Cast(activeItem.presIndexed, 'number', null) !== undefined ? true : false} /> @@ -2364,7 +2369,8 @@ export class PresBox extends ViewBoxBaseComponent() { clearTimeout(this._presTimer); }; - AddToMap = (treeViewDoc: Doc, index: number[]): Doc[] => { + AddToMap = (treeViewDoc: Doc, index: number[]) => { + if (!treeViewDoc.presentationTargetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. var indexNum = 0; for (let i = 0; i < index.length; i++) { indexNum += index[i] * 10 ** -i; @@ -2377,15 +2383,14 @@ export class PresBox extends ViewBoxBaseComponent() { this.dataDoc[this.presFieldKey] = new List(sorted); // this is a flat array of Docs } } - return this.childDocs; }; - RemFromMap = (treeViewDoc: Doc, index: number[]): Doc[] => { + RemFromMap = (treeViewDoc: Doc, index: number[]) => { + if (!treeViewDoc.presentationTargetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. if (!this._unmounting && this.isTree) { this._treeViewMap.delete(treeViewDoc); this.dataDoc[this.presFieldKey] = new List(this.sort(this._treeViewMap)); } - return this.childDocs; }; sort = (treeViewMap: Map) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]); -- cgit v1.2.3-70-g09d2 From c5c2c309cd88bbeb2f1b668cb040cffaac9c8470 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 4 Apr 2023 20:12:16 -0400 Subject: fixed using freeformview in sidebar of pdfs. fixed issues with dragging items out of schema and with selecting the schema view by clicking on headers. Fixed a lot of errors caused by using OmitKeys which masks type checking. fixed some pointerevent problems with treeview and freeformview --- src/client/documents/Documents.ts | 22 ++-- src/client/views/DocumentDecorations.tsx | 40 +++--- src/client/views/EditableView.tsx | 4 +- src/client/views/InkStrokeProperties.ts | 1 - src/client/views/InkingStroke.tsx | 13 +- src/client/views/MainView.tsx | 1 + src/client/views/PropertiesView.tsx | 73 ++--------- src/client/views/SidebarAnnos.tsx | 15 +-- src/client/views/StyleProvider.tsx | 2 +- src/client/views/TemplateMenu.tsx | 2 +- .../views/collections/CollectionCarousel3DView.tsx | 7 +- .../views/collections/CollectionCarouselView.tsx | 8 +- .../collections/CollectionStackedTimeline.tsx | 54 +++----- .../views/collections/CollectionTreeView.tsx | 24 ++-- src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 139 +++++++++++--------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 + .../collectionGrid/CollectionGridView.tsx | 9 +- .../collectionSchema/CollectionSchemaView.tsx | 99 +++------------ .../collectionSchema/SchemaColumnHeader.tsx | 10 +- src/client/views/nodes/AudioBox.tsx | 6 +- src/client/views/nodes/ComparisonBox.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 26 +--- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 12 +- src/client/views/nodes/MapBox/MapBox.tsx | 6 +- src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx | 5 +- src/client/views/nodes/PDFBox.tsx | 141 ++++++++++++++++----- src/client/views/nodes/ScreenshotBox.tsx | 18 ++- src/client/views/nodes/VideoBox.tsx | 12 +- src/client/views/nodes/WebBox.tsx | 14 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 27 ++-- src/client/views/pdf/PDFViewer.tsx | 15 ++- src/fields/Doc.ts | 9 +- 34 files changed, 389 insertions(+), 437 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 9b8b9c877..9cb480c4a 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1420,41 +1420,39 @@ export namespace DocUtils { export function DocumentFromField(target: Doc, fieldKey: string, proto?: Doc, options?: DocumentOptions): Doc | undefined { let created: Doc | undefined; - let layout: ((fieldKey: string) => string) | undefined; const field = target[fieldKey]; - const resolved = options || {}; + const resolved = options ?? {}; if (field instanceof ImageField) { created = Docs.Create.ImageDocument(field.url.href, resolved); - layout = ImageBox.LayoutString; + created.layout = ImageBox.LayoutString(fieldKey); } else if (field instanceof Doc) { created = field; } else if (field instanceof VideoField) { created = Docs.Create.VideoDocument(field.url.href, resolved); - layout = VideoBox.LayoutString; + created.layout = VideoBox.LayoutString(fieldKey); } else if (field instanceof PdfField) { created = Docs.Create.PdfDocument(field.url.href, resolved); - layout = PDFBox.LayoutString; + created.layout = PDFBox.LayoutString(fieldKey); } else if (field instanceof AudioField) { created = Docs.Create.AudioDocument(field.url.href, resolved); - layout = AudioBox.LayoutString; + created.layout = AudioBox.LayoutString(fieldKey); } else if (field instanceof RecordingField) { created = Docs.Create.RecordingDocument(field.url.href, resolved); - layout = RecordingBox.LayoutString; + created.layout = RecordingBox.LayoutString(fieldKey); } else if (field instanceof InkField) { created = Docs.Create.InkDocument(ActiveInkColor(), Doc.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), field.inkData, ActiveIsInkMask(), resolved); - layout = InkingStroke.LayoutString; + created.layout = InkingStroke.LayoutString(fieldKey); } else if (field instanceof List && field[0] instanceof Doc) { created = Docs.Create.StackingDocument(DocListCast(field), resolved); - layout = CollectionView.LayoutString; + created.layout = CollectionView.LayoutString(fieldKey); } else if (field instanceof MapField) { created = Docs.Create.MapDocument(DocListCast(field), resolved); - layout = MapBox.LayoutString; + created.layout = MapBox.LayoutString(fieldKey); } else { created = Docs.Create.TextDocument('', { ...{ _width: 200, _height: 25, _autoHeight: true }, ...resolved }); - layout = FormattedTextBox.LayoutString; + created.layout = FormattedTextBox.LayoutString(fieldKey); } if (created) { - created.layout = layout?.(fieldKey); created.title = fieldKey; proto && created.proto && (created.proto = Doc.GetProto(proto)); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 985e6f88f..9bc583ce5 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -31,6 +31,7 @@ import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { ImageBox } from './nodes/ImageBox'; import React = require('react'); +import { RichTextField } from '../../fields/RichTextField'; @observer export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> { @@ -127,19 +128,23 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } //@ts-ignore const titleField = +this._accumulatedTitle == this._accumulatedTitle ? +this._accumulatedTitle : this._accumulatedTitle; - Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true); - if (d.rootDoc.syncLayoutFieldWithTitle) { - const title = titleField.toString(); + if (titleField.toString().startsWith('')) { + const title = titleField.toString().replace(/\.?/, ''); const curKey = Doc.LayoutFieldKey(d.rootDoc); - if (curKey !== title && d.dataDoc[title] === undefined) { - d.rootDoc.layout = FormattedTextBox.LayoutString(title); - setTimeout(() => { - const val = d.dataDoc[curKey]; - d.dataDoc[curKey] = undefined; - d.dataDoc[title] = val; - }); + if (curKey !== title) { + if (title) { + if (d.dataDoc[title] === undefined || d.dataDoc[title] instanceof RichTextField || typeof d.dataDoc[title] === 'string') { + d.rootDoc.layoutKey = `layout_${title}`; + d.rootDoc[`layout_${title}`] = FormattedTextBox.LayoutString(title); + d.rootDoc[`${title}-nativeWidth`] = d.rootDoc[`${title}-nativeHeight`] = 0; + } + } else { + d.rootDoc.layoutKey = undefined; + } } + } else { + Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true); } }), 'title blur' @@ -453,17 +458,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P @action onPointerDown = (e: React.PointerEvent): void => { - const views = SelectionManager.Views().map(dv => dv.rootDoc); - this._inkDragDocs = views - .filter(doc => doc.type === DocumentType.INK) - .map(doc => { - if (InkStrokeProperties.Instance._lock) { - Doc.SetNativeHeight(doc, NumCast(doc._height)); - Doc.SetNativeWidth(doc, NumCast(doc._width)); - } - return { doc, x: NumCast(doc.x), y: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }; - }); - setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction); this.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; @@ -487,10 +481,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (!first) return false; let thisPt = { x: e.clientX - this._offX, y: e.clientY - this._offY }; var fixedAspect = Doc.NativeAspect(first.layoutDoc); - InkStrokeProperties.Instance._lock && - SelectionManager.Views() - .filter(dv => dv.rootDoc.type === DocumentType.INK) - .forEach(dv => (fixedAspect = Doc.NativeAspect(dv.rootDoc))); const resizeHdl = this._resizeHdlId.split(' ')[0]; if (fixedAspect && (resizeHdl === 'documentDecorations-bottomRightResizer' || resizeHdl === 'documentDecorations-topLeftResizer')) { diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index bb190e93b..164b6c57a 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -129,7 +129,7 @@ export class EditableView extends React.Component { this._editing = true; this.props.isEditingCallback?.(true); } - e.stopPropagation(); + // e.stopPropagation(); } }; @@ -215,7 +215,7 @@ export class EditableView extends React.Component { className={`editableView-container-editing${this.props.oneLine ? '-oneLine' : ''}`} ref={this._ref} style={{ display: this.props.display, textOverflow: this.props.overflow, minHeight: '10px', whiteSpace: 'nowrap', height: this.props.height || 'auto', maxHeight: this.props.maxHeight }} - onPointerDown={e => e.stopPropagation()} + //onPointerDown={this.stopPropagation} onClick={this.onClick} placeholder={this.props.placeholder}> {this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()} diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 1d8d52425..e6df0801c 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -19,7 +19,6 @@ export class InkStrokeProperties { return this._Instance || new InkStrokeProperties(); } - @observable _lock = false; @observable _controlButton = false; @observable _currentPoint = -1; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index e3642fdaf..2fd6cc4d6 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -25,10 +25,11 @@ import { action, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, HeightSym, WidthSym } from '../../fields/Doc'; import { InkData, InkField } from '../../fields/InkField'; -import { BoolCast, Cast, DocCast, NumCast, RTFCast, StrCast } from '../../fields/Types'; +import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; -import { DashColor, OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils'; +import { DashColor, returnFalse, setupMoveUpEvents } from '../../Utils'; import { CognitiveServices } from '../cognitive_services/CognitiveServices'; +import { Docs } from '../documents/Documents'; import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; import { Transform } from '../util/Transform'; @@ -41,13 +42,12 @@ import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles'; import './InkStroke.scss'; import { InkStrokeProperties } from './InkStrokeProperties'; import { InkTangentHandles } from './InkTangentHandles'; -import { DocComponentView, DocFocusOptions, DocumentView } from './nodes/DocumentView'; +import { DocComponentView } from './nodes/DocumentView'; import { FieldView, FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { PinProps, PresBox } from './nodes/trails'; import { StyleProp } from './StyleProvider'; import Color = require('color'); -import { Docs } from '../documents/Documents'; -import { PinProps, PresBox } from './nodes/trails'; @observer export class InkingStroke extends ViewBoxBaseComponent() { @@ -464,7 +464,8 @@ export class InkingStroke extends ViewBoxBaseComponent() { //top: (this.props.PanelHeight() - (lineHeightGuess * fsize + 20) * (this.props.NativeDimScaling?.() || 1)) / 2, }}> { @observable inOptions: boolean = false; @observable _controlButton: boolean = false; - @observable _lock: boolean = false; componentDidMount() { this.selectedDocListenerDisposer?.(); @@ -586,16 +585,6 @@ export class PropertiesView extends React.Component {
- {InkStrokeProperties.Instance._lock ? 'Unlock ratio' : 'Lock ratio'}
}> -
(InkStrokeProperties.Instance._lock = !InkStrokeProperties.Instance._lock))}> - -
- - {'Rotate 90Ëš'}
}> -
this.rotate(Math.PI / 2))}> - -
-
); } @@ -644,9 +633,6 @@ export class PropertiesView extends React.Component { @action upDownButtons = (dirs: string, field: string) => { switch (field) { - case 'rot': - this.rotate(dirs === 'up' ? 0.1 : -0.1); - break; case 'Xps': this.selectedDoc && (this.selectedDoc.x = NumCast(this.selectedDoc?.x) + (dirs === 'up' ? 10 : -10)); break; @@ -662,7 +648,6 @@ export class PropertiesView extends React.Component { const oldX = NumCast(this.selectedDoc?.x); const oldY = NumCast(this.selectedDoc?.y); this.selectedDoc && (this.selectedDoc._width = oldWidth + (dirs === 'up' ? 10 : -10)); - InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth) * NumCast(this.selectedDoc?._height)); const doc = this.selectedDoc; if (doc?.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) { const ink = Cast(doc.data, InkField)?.inkData; @@ -684,7 +669,6 @@ export class PropertiesView extends React.Component { const oX = NumCast(this.selectedDoc?.x); const oY = NumCast(this.selectedDoc?.y); this.selectedDoc && (this.selectedDoc._height = oHeight + (dirs === 'up' ? 10 : -10)); - InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight) * NumCast(this.selectedDoc?._width)); const docu = this.selectedDoc; if (docu?.type === DocumentType.INK && docu.x && docu.y && docu._height && docu._width) { const ink = Cast(docu.data, InkField)?.inkData; @@ -704,11 +688,7 @@ export class PropertiesView extends React.Component { }; getField(key: string) { - //if (this.selectedDoc) { return Field.toString(this.selectedDoc?.[key] as Field); - // } else { - // return undefined as Opt; - // } } @computed get shapeXps() { @@ -717,9 +697,6 @@ export class PropertiesView extends React.Component { @computed get shapeYps() { return this.getField('y'); } - @computed get shapeRot() { - return this.getField('rotation'); - } @computed get shapeHgt() { return this.getField('_height'); } @@ -732,18 +709,11 @@ export class PropertiesView extends React.Component { set shapeYps(value) { this.selectedDoc && (this.selectedDoc.y = Number(value)); } - set shapeRot(value) { - this.selectedDoc && (this.selectedDoc.rotation = Number(value)); - } set shapeWid(value) { - const oldWidth = NumCast(this.selectedDoc?._width); this.selectedDoc && (this.selectedDoc._width = Number(value)); - InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth); } set shapeHgt(value) { - const oldHeight = NumCast(this.selectedDoc?._height); this.selectedDoc && (this.selectedDoc._height = Number(value)); - InkStrokeProperties.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight); } @computed get hgtInput() { @@ -790,30 +760,6 @@ export class PropertiesView extends React.Component { 'Y:' ); } - @computed get rotInput() { - return this.inputBoxDuo( - 'rot', - this.shapeRot, - (val: string) => { - if (!isNaN(Number(val))) { - this.rotate(Number(val) - Number(this.shapeRot)); - this.shapeRot = val; - } - return true; - }, - '∠:', - 'rot', - this.shapeRot, - (val: string) => { - if (!isNaN(Number(val))) { - this.rotate(Number(val) - Number(this.shapeRot)); - this.shapeRot = val; - } - return true; - }, - '' - ); - } @observable private _fillBtn = false; @observable private _lineBtn = false; @@ -1080,10 +1026,9 @@ export class PropertiesView extends React.Component { @computed get transformEditor() { return (
- {this.controlPointsButton} + {this.isInk ? this.controlPointsButton : null} {this.hgtInput} {this.XpsInput} - {this.rotInput}
); } @@ -1194,17 +1139,15 @@ export class PropertiesView extends React.Component {
)} - {this.isInk ? ( -
-
(this.openTransform = !this.openTransform))} style={{ backgroundColor: this.openTransform ? 'black' : '' }}> - Transform -
- -
+
+
(this.openTransform = !this.openTransform))} style={{ backgroundColor: this.openTransform ? 'black' : '' }}> + Transform +
+
- {this.openTransform ?
{this.transformEditor}
: null}
- ) : null} + {this.openTransform ?
{this.transformEditor}
: null} +
); } diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 02dd15960..48c0150e6 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -5,7 +5,7 @@ import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { RichTextField } from '../../fields/RichTextField'; import { DocCast, NumCast, StrCast } from '../../fields/Types'; -import { emptyFunction, OmitKeys, returnAll, returnOne, returnTrue, returnZero } from '../../Utils'; +import { emptyFunction, returnAll, returnFalse, returnOne, returnTrue, returnZero } from '../../Utils'; import { Docs, DocUtils } from '../documents/Documents'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { LinkManager } from '../util/LinkManager'; @@ -26,6 +26,7 @@ interface ExtraProps { // usePanelWidth: boolean; showSidebar: boolean; nativeWidth: number; + usePanelWidth?: boolean; whenChildContentsActiveChanged: (isActive: boolean) => void; ScreenToLocalTransform: () => Transform; sidebarAddDocument: (doc: Doc | Doc[], suffix: string) => boolean; @@ -158,13 +159,10 @@ export class SidebarAnnos extends React.Component { .ScreenToLocalTransform() .translate(Doc.NativeWidth(this.props.dataDoc), 0) .scale(this.props.NativeDimScaling?.() || 1); - // panelWidth = () => !this.props.layoutDoc._showSidebar ? 0 : - // this.props.usePanelWidth ? this.props.PanelWidth() : - // (NumCast(this.props.layoutDoc.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth() / NumCast(this.props.layoutDoc.nativeWidth); panelWidth = () => !this.props.showSidebar ? 0 - : this.props.layoutDoc.type === DocumentType.RTF || this.props.layoutDoc.type === DocumentType.MAP + : this.props.usePanelWidth // [DocumentType.RTF, DocumentType.MAP].includes(this.props.layoutDoc.type as any) ? this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) : ((NumCast(this.props.nativeWidth) - Doc.NativeWidth(this.props.dataDoc)) * this.props.PanelWidth()) / NumCast(this.props.nativeWidth); panelHeight = () => this.props.PanelHeight() - this.filtersHeight(); @@ -224,20 +222,21 @@ export class SidebarAnnos extends React.Component {
, props: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); if (docColor) return docColor; const docView = props?.DocumentView?.(); - const backColor = backgroundCol() || docView?.props.styleProvider?.(docView.props.treeViewDoc, docView.props, 'backgroundColor'); + const backColor = backgroundCol() || docView?.props.styleProvider?.(docView.props.treeViewDoc, docView.props, StyleProp.BackgroundColor); if (!backColor) return undefined; return lightOrDark(backColor); case StyleProp.Hidden: diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 681ff66e0..45db240a9 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -79,7 +79,7 @@ export class TemplateMenu extends React.Component { }; componentDidMount() { !this._addedKeys && (this._addedKeys = new ObservableSet()); - Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document))) + [...Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document))), ...Array.from(Object.keys(this.props.docViews[0].props.Document))] .filter(key => key.startsWith('layout_')) .map(key => runInAction(() => this._addedKeys.add(key.replace('layout_', '')))); } diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 57ff1b292..a266c9207 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -5,7 +5,7 @@ import * as React from 'react'; import { Doc } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { NumCast, ScriptCast, StrCast } from '../../../fields/Types'; -import { OmitKeys, returnFalse, Utils } from '../../../Utils'; +import { returnFalse, returnZero, Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { DocumentView } from '../nodes/DocumentView'; import { StyleProp } from '../StyleProvider'; @@ -43,7 +43,10 @@ export class CollectionCarousel3DView extends CollectionSubView() { const displayDoc = (childPair: { layout: Doc; data: Doc }) => { return (
this.currentTime; - @computed get renderDictation() { - const dictation = Cast(this.dataDoc[this.props.dictationKey], Doc, null); - return !dictation ? null : ( -
- -
- ); - } - // renders selection region on timeline @computed get selectionContainer() { const markerEnd = CollectionStackedTimeline.SelectingRegion === this ? this.currentTime : this._markerEnd; @@ -638,7 +606,6 @@ export class CollectionStackedTimeline extends CollectionSubView )} - {/* {this.renderDictation} */}
// renders anchor LabelBox renderInner = computedFn(function (this: StackedTimelineAnchor, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) { const anchor = observable({ view: undefined as any }); - const focusFunc = (doc: Doc, options: DocFocusOptions) => this.props.playLink(mark); + const focusFunc = (doc: Doc, options: DocFocusOptions): number | undefined => { + this.props.playLink(mark); + return undefined; + }; return { anchor, view: ( (anchor.view = r))} Document={mark} DataDoc={undefined} + docViewPath={returnEmptyDoclist} pointerEvents={this.noEvents ? returnNone : undefined} styleProvider={this.props.styleProvider} renderDepth={this.props.renderDepth + 1} @@ -837,7 +810,16 @@ class StackedTimelineAnchor extends React.Component PanelHeight={height} fitWidth={returnTrue} ScreenToLocalTransform={screenXf} + addDocTab={returnFalse} + pinToPres={emptyFunction} + whenChildContentsActiveChanged={emptyFunction} focus={focusFunc} + isContentActive={returnFalse} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + searchFilterDocs={returnEmptyDoclist} + docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} rootSelected={returnFalse} onClick={script} onDoubleClick={this.props.layoutDoc.autoPlayAnchors ? undefined : doublescript} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 553967b95..4a11e8f0b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -7,7 +7,7 @@ import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, OmitKeys, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue } from '../../../Utils'; +import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; @@ -384,12 +384,12 @@ export class CollectionTreeView extends CollectionSubView { + @computed get content() { const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor); const pointerEvents = () => (!this.props.isContentActive() && !SnappingManager.GetIsDragging() ? 'none' : undefined); const titleBar = this.props.treeViewHideTitle || this.doc.treeViewHideTitle ? null : this.titleBar; - return [ -
+ return ( +
{!this.buttonMenu && !this.noviceExplainer ? null : (
r && (this._headerHeight = Number(getComputedStyle(r).height.replace(/px/, ''))))}> {this.buttonMenu} @@ -428,9 +428,9 @@ export class CollectionTreeView extends CollectionSubView
-
, - ]; - }; +
+ ); + } render() { TraceMobx(); @@ -439,7 +439,11 @@ export class CollectionTreeView extends CollectionSubView {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? ( - {this.contentFunc} + {this.content} ) : ( - this.contentFunc() + this.content )}
); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 51624689e..bc25ad43a 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -45,7 +45,7 @@ interface CollectionViewProps_ extends FieldViewProps { // property overrides for child documents childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox) - childDocumentsActive?: () => boolean; // whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode) + childDocumentsActive?: () => boolean | undefined; // whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode) childFitWidth?: (child: Doc) => boolean; childShowTitle?: () => string; childOpacity?: () => number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index aed3683d4..d39668a5d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,6 @@ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { DateField } from '../../../../fields/DateField'; @@ -53,10 +53,14 @@ import { MarqueeView } from './MarqueeView'; import React = require('react'); export type collectionFreeformViewProps = { + noPointerWheel?: () => boolean; // turn off pointerwheel interactions (see PDFViewer) + NativeWidth?: () => number; + NativeHeight?: () => number; + originTopLeft?: boolean; annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; childPointerEvents?: string; - scaleField?: string; + viewField?: string; noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) engineProps?: any; getScrollHeight?: () => number | undefined; @@ -97,8 +101,14 @@ export class CollectionFreeFormView extends CollectionSubView (this.fitContentsToBox ? true : false); // panx, pany, zoomscale all attempt to get values first from the layout controller, then from the layout/dataDoc (or template layout doc), and finally from the resolved template data document. // this search order, for example, allows icons of cropped images to find the panx/pany/zoom on the cropped image's data doc instead of the usual layout doc because the zoom/panX/panY define the cropped image - panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX, NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1)); - panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY, NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1)); + panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1)); + panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1)); zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1)); contentTransform = () => - !this.cachedCenteringShiftX && !this.cachedCenteringShiftY && this.zoomScaling() === 1 - ? '' - : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; + this.props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; getTransform = () => this.cachedGetTransform.copy(); getLocalTransform = () => this.cachedGetLocalTransform.copy(); getContainerTransform = () => this.cachedGetContainerTransform.copy(); @@ -293,7 +301,7 @@ export class CollectionFreeFormView extends CollectionSubView { - options.docTransform = new Transform(-NumCast(this.rootDoc.panX) + NumCast(anchor.x), -NumCast(this.rootDoc.panY) + NumCast(anchor.y), 1); + 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 = undefined; return res; @@ -301,7 +309,7 @@ export class CollectionFreeFormView extends CollectionSubView { const xfToCollection = options?.docTransform ?? Transform.Identity(); - const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined }; + const savedState = { panX: NumCast(this.Document[this.panXFieldKey]), panY: NumCast(this.Document[this.panYFieldKey]), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined }; const cantTransform = this.fitContentsToBox || ((this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc); const { panX, panY, scale } = cantTransform || (!options.willPan && !options.willZoomCentered) ? savedState : this.calculatePanIntoView(anchor, xfToCollection, options?.willZoomCentered ? options?.zoomScale || 0.75 : undefined); @@ -772,7 +780,7 @@ export class CollectionFreeFormView extends CollectionSubView= 0.05 || localTransform.Scale > this.zoomScaling()) { const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20); this.props.Document[this.scaleFieldKey] = Math.abs(safeScale); - this.setPan(-localTransform.TranslateX / safeScale, NumCast(this.props.Document.scrollTop) * safeScale || -localTransform.TranslateY / safeScale); + this.setPan(-localTransform.TranslateX / safeScale, (this.props.originTopLeft ? undefined : NumCast(this.props.Document.scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); } }; @action onPointerWheel = (e: React.WheelEvent): void => { - if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom + if (this.props.noPointerWheel?.() || this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return; e.stopPropagation(); @@ -995,7 +1003,7 @@ export class CollectionFreeFormView extends CollectionSubView= panX + panelDim[0] / 2) panX = ranges.xrange.max + panelDim[0] / 2; // snaps pan position of range of content goes out of bounds - else if (ranges.xrange.max <= panX - panelDim[0] / 2) panX = ranges.xrange.min - panelDim[0] / 2; - if (ranges.yrange.min >= panY + panelDim[1] / 2) panY = ranges.yrange.max + panelDim[1] / 2; - else if (ranges.yrange.max <= panY - panelDim[1] / 2) panY = ranges.yrange.min - panelDim[1] / 2; + const panelWidMax = (this.props.PanelWidth() / this.zoomScaling()) * (this.props.originTopLeft ? 2 / this.nativeDimScaling : 1); + const panelWidMin = (this.props.PanelWidth() / this.zoomScaling()) * (this.props.originTopLeft ? 0 : 1); + const panelHgtMax = (this.props.PanelHeight() / this.zoomScaling()) * (this.props.originTopLeft ? 2 / this.nativeDimScaling : 1); + const panelHgtMin = (this.props.PanelHeight() / this.zoomScaling()) * (this.props.originTopLeft ? 0 : 1); + if (ranges.xrange.min >= 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); + else if (ranges.yrange.max <= panY - panelHgtMin / 2) panY = ranges.yrange.min - (this.props.originTopLeft ? panelHgtMax / 2 : panelHgtMin / 2); } } if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc || DocListCast(Doc.MyOverlayDocs?.data).includes(this.Document)) { @@ -1078,8 +1089,8 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || this.props.ContainingCollectionDoc._panX !== undefined) { this.setPan( - NumCast(this.layoutDoc._panX) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale - NumCast(this.layoutDoc._panY) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(), + 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(), nudgeTime, true ); @@ -1106,12 +1117,14 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).slice(); docs.sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); - let zlast = docs.length ? Math.max(docs.length, NumCast(docs[docs.length - 1].zIndex)) : 1; - if (zlast - docs.length > 100) { - for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1; - zlast = docs.length + 1; + let zlast = docs.length ? Math.max(docs.length, NumCast(docs.lastElement().zIndex)) : 1; + if (docs.lastElement() !== doc) { + if (zlast - docs.length > 100) { + for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1; + zlast = docs.length + 1; + } + doc.zIndex = zlast + 1; } - doc.zIndex = zlast + 1; } }; @@ -1134,8 +1147,8 @@ export class CollectionFreeFormView extends CollectionSubView { @@ -1158,8 +1171,8 @@ export class CollectionFreeFormView extends CollectionSubView screen.bot ? Math.min(ph / 10, maxYShift / 2) : 0; @@ -1171,8 +1184,8 @@ export class CollectionFreeFormView extends CollectionSubView { if (cbounds) { const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; - const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; + const p = [NumCast(this.layoutDoc[this.panXFieldKey]), NumCast(this.layoutDoc[this.panYFieldKey])]; const pbounds = { x: cbounds.x - p[0] + c[0], y: cbounds.y - p[1] + c[1], @@ -1511,8 +1524,8 @@ export class CollectionFreeFormView extends CollectionSubView NumCast(doc._height))) + 20; const dim = Math.ceil(Math.sqrt(docs.length)); docs.forEach((doc, i) => { - doc.x = NumCast(this.Document._panX) + (i % dim) * width - (width * dim) / 2; - doc.y = NumCast(this.Document._panY) + Math.floor(i / dim) * height - (height * dim) / 2; + doc.x = NumCast(this.Document[this.panXFieldKey]) + (i % dim) * width - (width * dim) / 2; + doc.y = NumCast(this.Document[this.panYFieldKey]) + Math.floor(i / dim) * height - (height * dim) / 2; }); }; @@ -1675,7 +1688,7 @@ export class CollectionFreeFormView extends CollectionSubView { - this.props.Document._panX = this.props.Document._panY = 0; + this.props.Document[this.panXFieldKey] = this.props.Document[this.panYFieldKey] = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: 'compress-arrows-alt', @@ -1795,11 +1808,11 @@ export class CollectionFreeFormView extends CollectionSubView !this._renderCutoffData.get(doc[Id])) && setTimeout(this.incrementalRender, 1); }); - children = () => { + get children() { this.incrementalRender(); - const children = typeof this.props.children === 'function' ? ((this.props.children as any)() as JSX.Element[]) : []; + 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, ]; - }; + } @computed get placeholder() { return ( @@ -1843,6 +1856,7 @@ export class CollectionFreeFormView extends CollectionSubView this.nativeDimScaling; private groupDropDisposer?: DragManager.DragDropDisposer; protected createGroupEventsTarget = (ele: HTMLDivElement) => { @@ -1912,7 +1927,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.createDashEventsTarget(r); // prevent wheel events from passivly propagating up through containers - r?.addEventListener('wheel', (e: WheelEvent) => this.props.isSelected() && e.preventDefault(), { passive: false }); + !this.props.isAnnotationOverlay && r?.addEventListener('wheel', (e: WheelEvent) => this.props.isSelected() && e.preventDefault(), { passive: false }); }} onWheel={this.onPointerWheel} onClick={this.onClick} @@ -1985,7 +2000,8 @@ interface CollectionFreeFormViewPannableContentsProps { transform: () => string; zoomScaling: () => number; viewDefDivClick?: ScriptField; - children: () => JSX.Element[]; + children?: React.ReactNode | undefined; + //children: () => JSX.Element[]; transition?: string; presPaths: () => JSX.Element | null; presPinView?: boolean; @@ -2079,7 +2095,7 @@ class CollectionFreeFormViewPannableContents extends React.Component - {this.props.children()} + {this.props.children} {!this.props.brushView.width ? null : (
number; PanelHeight: () => number; isAnnotationOverlay?: boolean; + nativeDimScaling: () => number; zoomScaling: () => number; layoutDoc: Doc; cachedCenteringShiftX: number; @@ -2124,10 +2141,10 @@ class CollectionFreeFormBackgroundGrid extends React.Component { + // if (this.props.pointerEvents?.() === 'none') return; this._downX = this._lastX = e.clientX; this._downY = this._lastY = e.clientY; if (!(e.nativeEvent as any).marqueeHit) { @@ -345,6 +346,7 @@ export class MarqueeView extends React.Component { + if (this.props.pointerEvents?.() === 'none') return; if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { if (Doc.ActiveTool === InkTool.None) { if (!(e.nativeEvent as any).marqueeHit) { diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 9468c5f06..e8ae88ae5 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { Doc, Opt } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../../Utils'; +import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; @@ -186,7 +186,10 @@ export class CollectionGridView extends CollectionSubView() { getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) { return ( ); } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index d47c9762c..fd9bcf681 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,23 +1,20 @@ import React = require('react'); import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, ObservableMap, trace, untracked } from 'mobx'; +import { action, computed, observable, ObservableMap, untracked } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc, DocListCast, Field, StrListCast } from '../../../../fields/Doc'; +import { computedFn } from 'mobx-utils'; +import { Doc, Field, StrListCast } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; -import { RichTextField } from '../../../../fields/RichTextField'; import { listSpec } from '../../../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { ImageField } from '../../../../fields/URLField'; import { emptyFunction, returnDefault, returnEmptyDoclist, returnEmptyString, returnFalse, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils'; import { Docs, DocUtils } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { SelectionManager } from '../../../util/SelectionManager'; -import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; -import { ContextMenuProps } from '../../ContextMenuItem'; import { EditableView } from '../../EditableView'; import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -215,9 +212,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - addNewKey = (key: string, defaultVal: any) => { - this.childDocs.forEach(doc => (doc[key] = defaultVal)); - }; + addNewKey = (key: string, defaultVal: any) => this.childDocs.forEach(doc => (doc[key] = defaultVal)); @undoBatch @action @@ -303,9 +298,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - addRowRef = (doc: Doc, ref: HTMLDivElement) => { - this._rowEles.set(doc, ref); - }; + addRowRef = (doc: Doc, ref: HTMLDivElement) => this._rowEles.set(doc, ref); @action setColRef = (index: number, ref: HTMLDivElement) => { @@ -405,68 +398,12 @@ export class CollectionSchemaView extends CollectionSubView() { menuCallback = (x: number, y: number) => { ContextMenu.Instance.clearItems(); - const layoutItems: ContextMenuProps[] = []; - const docItems: ContextMenuProps[] = []; - const dataDoc = this.props.DataDoc || this.props.Document; - - DocUtils.addDocumentCreatorMenuItems( - doc => { - FormattedTextBox.SelectOnLoad = StrCast(doc[Id]); - return this.addRow(doc); - }, - this.addRow, - x, - y, - true - ); - Array.from(Object.keys(Doc.GetProto(dataDoc))) - .filter(fieldKey => dataDoc[fieldKey] instanceof RichTextField || dataDoc[fieldKey] instanceof ImageField || typeof dataDoc[fieldKey] === 'string') - .map(fieldKey => - docItems.push({ - description: ':' + fieldKey, - event: () => { - const created = DocUtils.DocumentFromField(dataDoc, fieldKey, Doc.GetProto(this.props.Document)); - if (created) { - if (this.props.Document.isTemplateDoc) { - Doc.MakeMetadataFieldTemplate(created, this.props.Document); - } - return this.addRow(created); - } - }, - icon: 'compress-arrows-alt', - }) - ); - Array.from(Object.keys(Doc.GetProto(dataDoc))) - .filter(fieldKey => DocListCast(dataDoc[fieldKey]).length) - .map(fieldKey => - docItems.push({ - description: ':' + fieldKey, - event: () => { - const created = Docs.Create.CarouselDocument([], { _width: 400, _height: 200, title: fieldKey }); - if (created) { - const container = this.props.Document.resolvedDataDoc ? Doc.GetProto(this.props.Document) : this.props.Document; - if (container.isTemplateDoc) { - Doc.MakeMetadataFieldTemplate(created, container); - return Doc.AddDocToList(container, Doc.LayoutFieldKey(container), created); - } - return this.addRow(created) || false; - } - }, - icon: 'compress-arrows-alt', - }) - ); - !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Doc Fields ...', subitems: docItems, icon: 'eye' }); - !Doc.noviceMode && ContextMenu.Instance.addItem({ description: 'Containers ...', subitems: layoutItems, icon: 'eye' }); + DocUtils.addDocumentCreatorMenuItems(doc => this.addRow(doc), this.addRow, x, y, true); + ContextMenu.Instance.setDefaultItem('::', (name: string): void => { Doc.GetProto(this.props.Document)[name] = ''; - const created = Docs.Create.TextDocument('', { title: name, _autoHeight: true }); - if (created) { - if (this.props.Document.isTemplateDoc) { - Doc.MakeMetadataFieldTemplate(created, this.props.Document); - } - this.addRow(created); - } + this.addRow(Docs.Create.TextDocument('', { title: name, _autoHeight: true })); }); ContextMenu.Instance.displayMenu(x, y, undefined, true); }; @@ -543,9 +480,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - closeColumnMenu = () => { - this._columnMenuIndex = undefined; - }; + closeColumnMenu = () => (this._columnMenuIndex = undefined); @action openFilterMenu = (index: number) => { @@ -596,19 +531,14 @@ export class CollectionSchemaView extends CollectionSubView() { getFieldFilters = (field: string) => StrListCast(this.Document._docFilters).filter(filter => filter.split(':')[0] == field); removeFieldFilters = (field: string) => { - this.getFieldFilters(field).forEach(filter => { - Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove'); - }); + this.getFieldFilters(field).forEach(filter => Doc.setDocFilter(this.Document, field, filter.split(':')[1], 'remove')); }; onFilterKeyDown = (e: React.KeyboardEvent) => { + //prettier-ignore switch (e.key) { - case 'Enter': - this.closeFilterMenu(true); - break; - case 'Escape': - this.closeFilterMenu(false); - break; + case 'Enter' : this.closeFilterMenu(true); break; + case 'Escape': this.closeFilterMenu(false);break; } }; @@ -903,6 +833,7 @@ interface CollectionSchemaViewDocsProps { class CollectionSchemaViewDocs extends React.Component { tableWidthFunc = () => this.props.schema.tableWidth; rowHeightFunc = () => CollectionSchemaView._rowHeight; + childScreenToLocal = computedFn((index: number) => () => this.props.schema.props.ScreenToLocalTransform().translate(0, -CollectionSchemaView._rowHeight - index * this.rowHeightFunc())); render() { return (
@@ -932,7 +863,7 @@ class CollectionSchemaViewDocs extends React.Component @action onPointerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction); + setupMoveUpEvents(this, e, e => this.props.dragColumn(e, this.props.columnIndex), emptyFunction, emptyFunction, false); }; render() { return ( -
{ - col && this.props.setColRef(this.props.columnIndex, col); - }}> +
col && this.props.setColRef(this.props.columnIndex, col)}>
this.props.resizeColumn(e, this.props.columnIndex)}>
{this.fieldKey}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 384975b45..a6acf882c 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -7,7 +7,7 @@ import { Doc, DocListCast } from '../../../fields/Doc'; import { ComputedField } from '../../../fields/ScriptField'; import { Cast, DateCast, NumCast } from '../../../fields/Types'; import { AudioField, nullAudio } from '../../../fields/URLField'; -import { emptyFunction, formatTime, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../Utils'; +import { emptyFunction, formatTime, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { Networking } from '../../Network'; import { DragManager } from '../../util/DragManager'; @@ -19,7 +19,6 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import './AudioBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; -import { SelectionManager } from '../../util/SelectionManager'; import { PinProps, PresBox } from './trails'; /** @@ -655,7 +654,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent (this._stackedTimeline = r))} - {...OmitKeys(this.props, ['CollectionFreeFormDocumentView']).omit} + {...this.props} + CollectionFreeFormDocumentView={undefined} fieldKey={this.annotationKey} dictationKey={this.fieldKey + '-dictation'} mediaPath={this.path} diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index ecffe6c4f..ace388c57 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -3,7 +3,7 @@ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../../fields/Doc'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, OmitKeys, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; +import { emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { SnappingManager } from '../../util/SnappingManager'; @@ -122,7 +122,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { //whichDoc !== targetDoc && r?.focus(whichDoc, { instant: true }); }} - {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight']).omit} + {...this.props} + NativeWidth={returnZero} + NativeHeight={returnZero} isContentActive={returnFalse} isDocumentActive={returnFalse} styleProvider={this.docStyleProvider} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 091a6b050..c7bf37a45 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -12,7 +12,7 @@ import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { AudioField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; -import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils'; +import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils'; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { DocServer } from '../../DocServer'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -512,7 +512,6 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); - !Doc.noviceMode && - appearanceItems.push({ - description: 'Add a Field', - event: () => { - const alias = Doc.MakeAlias(this.rootDoc); - alias.layout = FormattedTextBox.LayoutString('newfield'); - alias.title = 'newfield'; - alias._height = 35; - alias._width = 100; - alias.syncLayoutFieldWithTitle = true; - alias.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc.width); - alias.y = NumCast(this.rootDoc.y); - this.props.addDocument?.(alias); - }, - icon: 'eye', - }); LinkManager.Links(this.Document).length && appearanceItems.splice(0, 0, { description: `${this.layoutDoc.hideLinkButton ? 'Show' : 'Hide'} Link Button`, event: action(() => (this.layoutDoc.hideLinkButton = !this.layoutDoc.hideLinkButton)), icon: 'eye' }); !appearance && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' }); @@ -863,7 +846,7 @@ export class DocumentViewInternal extends DocComponent (this.disableClickScriptFunc ? undefined : this.onClickHandler); setHeight = (height: number) => (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); - isContentActive = (outsideReaction?: boolean) => { + isContentActive = (outsideReaction?: boolean): boolean | undefined => { return this.props.isContentActive() === false ? false : Doc.ActiveTool !== InkTool.None || @@ -1064,7 +1047,7 @@ export class DocumentViewInternal extends DocComponent, props: Opt, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption'); + captionStyleProvider = (doc: Opt, props: Opt, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption'); @computed get innards() { TraceMobx(); const ffscale = () => this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1; @@ -1079,7 +1062,7 @@ export class DocumentViewInternal extends DocComponent
); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index e53422ab7..8d3534a5c 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -20,7 +20,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { select: (isCtrlPressed: boolean) => void; isContentActive: (outsideReaction?: boolean) => boolean | undefined; - isDocumentActive?: () => boolean; + isDocumentActive?: () => boolean | undefined; isSelected: (outsideReaction?: boolean) => boolean; setHeight?: (height: number) => void; NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to DocumentViewInternalsProps diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 48e54b722..b5193cd20 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -11,7 +11,7 @@ import { ComputedField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { DashColor, emptyFunction, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; +import { DashColor, emptyFunction, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -409,8 +409,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent [this.content]; - private _mainCont: React.RefObject = React.createRef(); private _annotationLayer: React.RefObject = React.createRef(); @observable _marqueeing: number[] | undefined; @@ -473,7 +471,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent - {this.contentFunc} + {this.content} {this.annotationLayer} {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : ( diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index ea8f47b39..36be7d257 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -8,7 +8,7 @@ import { Doc, DocListCast, Opt, WidthSym } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { emptyFunction, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; @@ -635,7 +635,8 @@ export class MapBox extends ViewBoxAnnotatableComponent ( (this._stack = r)} - {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit} + {...this.props} + setContentView={emptyFunction} Document={this.props.place} DataDoc={undefined} fieldKey="data" diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 5f207cc0d..a254edd87 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -5,16 +5,20 @@ import * as Pdfjs from 'pdfjs-dist'; import 'pdfjs-dist/web/pdf_viewer.css'; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; -import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; +import { InkTool } from '../../../fields/InkField'; +import { ComputedField } from '../../../fields/ScriptField'; +import { Cast, FieldValue, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField, PdfField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils'; +import { emptyFunction, returnFalse, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; -import { DocumentType } from '../../documents/DocumentTypes'; +import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { KeyCodes } from '../../util/KeyCodes'; +import { SelectionManager } from '../../util/SelectionManager'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { CollectionFreeFormView } from '../collections/collectionFreeForm'; +import { CollectionStackingView } from '../collections/CollectionStackingView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; @@ -41,7 +45,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent; private _pdfViewer: PDFViewer | undefined; private _searchRef = React.createRef(); - private _selectReactionDisposer: IReactionDisposer | undefined; + private _disposers: { [name: string]: IReactionDisposer } = {}; private _sidebarRef = React.createRef(); @observable private _searching: boolean = false; @@ -184,11 +188,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent disposer?.()); } componentDidMount() { this.props.setContentView?.(this); - this._selectReactionDisposer = reaction( + this._disposers.select = reaction( () => this.props.isSelected(), () => { document.removeEventListener('keydown', this.onKeyDown); @@ -196,6 +200,16 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.rootDoc.scrollTop, + () => { + if (!(ComputedField.WithoutComputed(() => FieldValue(this.props.Document[this.SidebarKey + '-panY'])) instanceof ComputedField)) { + this.props.Document[this.SidebarKey + '-panY'] = ComputedField.MakeFunction('this.scrollTop'); + } + this.props.Document[this.SidebarKey + '-viewScale'] = 1; + this.props.Document[this.SidebarKey + '-panX'] = 0; + } + ); } brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._pdfViewer?.brushView(view); @@ -303,7 +317,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { + sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => { if (!this.layoutDoc._showSidebar) this.toggleSidebar(); return this.addDocument(doc, sidebarKey); }; @@ -428,6 +442,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent { const funcs: ContextMenuProps[] = []; + funcs.push({ + description: 'Toggle Sidebar Type', + event: () => (this.rootDoc.sidebarViewType = this.rootDoc.sidebarViewType === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform), + icon: 'expand-arrows-alt', + }); funcs.push({ description: 'Copy path', event: () => this.pdfUrl && Utils.CopyText(Utils.prepend('') + this.pdfUrl.url.pathname), icon: 'expand-arrows-alt' }); funcs.push({ description: 'update icon', event: () => this.pdfUrl && this.updateIcon(), icon: 'expand-arrows-alt' }); //funcs.push({ description: "Toggle Sidebar ", event: () => this.toggleSidebar(), icon: "expand-arrows-alt" }); @@ -467,12 +486,87 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.sidebarNativeWidth; + sidebarNativeHeightFunc = () => this.sidebarNativeHeight; + sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey); + sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey); + sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate((this.sidebarWidth() - this.props.PanelWidth()) / this.pdfScale, 0); + @computed get sidebarCollection() { + const renderComponent = (tag: string) => { + const ComponentTag = tag === CollectionViewType.Freeform ? CollectionFreeFormView : CollectionStackingView; + return ComponentTag === CollectionStackingView ? ( + + ) : ( +
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.props.DocumentView?.()!, false), true)}> + +
+ ); + }; + return ( +
+ {renderComponent(StrCast(this.layoutDoc.sidebarViewType))} +
+ ); + } isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected() || (this.props.renderDepth === 0 && LightboxView.IsLightboxDocView(this.props.docViewPath())); @computed get renderPdfView() { TraceMobx(); const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; const scale = previewScale * (this.props.NativeDimScaling?.() || 1); - return ( + return !this._pdf ? null : (
-
- -
+
{this.sidebarCollection}
{this.settingsPanel()}
); @@ -535,21 +614,17 @@ export class PDFBox extends ViewBoxAnnotatableComponent>(); render() { TraceMobx(); - if (this._pdf) { - if (!this.props.thumbShown?.()) { - return this.renderPdfView; - } - return null; - } + if (this.props.thumbShown?.()) return null; + const pdfView = this.renderPdfView; const href = this.pdfUrl?.url.href; - if (href) { + if (!pdfView && href) { if (PDFBox.pdfcache.get(href)) setTimeout(action(() => (this._pdf = PDFBox.pdfcache.get(href)))); else { if (!PDFBox.pdfpromise.get(href)) PDFBox.pdfpromise.set(href, Pdfjs.getDocument(href).promise); PDFBox.pdfpromise.get(href)?.then(action((pdf: any) => PDFBox.pdfcache.set(href, (this._pdf = pdf)))); } } - return this.renderTitleBox; + return pdfView ?? this.renderTitleBox; } } diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 61e4894f0..db11a7776 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -11,7 +11,7 @@ import { ComputedField } from '../../../fields/ScriptField'; import { Cast, NumCast } from '../../../fields/Types'; import { AudioField, VideoField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, OmitKeys, returnFalse, returnOne } from '../../../Utils'; +import { emptyFunction, returnFalse, returnOne, returnZero } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; @@ -277,7 +277,6 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent [this.threed, this.content]; videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '-nativeHeight'], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + '-nativeWidth'], this.layoutDoc[WidthSym]())) * this.props.PanelWidth(); formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight()); render() { @@ -287,7 +286,10 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent
- {this.contentFunc} + <> + {this.threed} + {this.content} +
{!(this.dataDoc[this.fieldKey + '-dictation'] instanceof Doc) ? null : ( )} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 0b88f5fe3..0570c7fcb 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -9,7 +9,7 @@ import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { AudioField, ImageField, VideoField } from '../../../fields/URLField'; -import { emptyFunction, formatTime, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; +import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; @@ -894,8 +894,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent this._playing; - contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content]; - scaling = () => this.props.NativeDimScaling?.() || 1; panelWidth = () => (this.props.PanelWidth() * this.heightPercent) / 100; @@ -1068,7 +1066,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent - {this.contentFunc} + {this.youtubeVideoId ? this.youtubeContent : this.content}
{this.annotationLayer} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index d57518a8d..66d0fd385 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -11,7 +11,7 @@ import { listSpec } from '../../../fields/Schema'; import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField, WebField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils'; +import { emptyFunction, getWordAtPoint, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; @@ -305,7 +305,9 @@ export class WebBox extends ViewBoxAnnotatableComponent string[]) => ( + const renderAnnotations = (docFilters: () => string[]) => ( this.props.Document._fitContentsToBox; + fitContentsToBox = () => BoolCast(this.props.Document._fitContentsToBox); sidebarContentScaling = () => (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => { if (!this.layoutDoc._showSidebar) this.toggleSidebar(); - // console.log("printting allSideBarDocs"); - // console.log(this.allSidebarDocs); return this.addDocument(doc, sidebarKey); }; sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey); @@ -1785,8 +1783,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent @@ -1800,33 +1798,36 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent ) : (
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.props.DocumentView?.()!, false), true)}> { return this.props.styleProvider?.(doc, props, property); }; - renderAnnotations = (docFilters?: () => string[], mixBlendMode?: any, display?: string) => ( + renderAnnotations = (docFilters: () => string[], mixBlendMode?: any, display?: string) => (
{ pointerEvents: Doc.ActiveTool !== InkTool.None ? 'all' : undefined, }}> { PanelHeight={this.panelHeight} PanelWidth={this.panelWidth} ScreenToLocalTransform={this.overlayTransform} + isAnyChildContentActive={returnFalse} + isAnnotationOverlayScrollable={true} dropAction={'alias'} docFilters={docFilters} select={emptyFunction} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 553c4525c..cc024d83a 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1213,7 +1213,7 @@ export namespace Doc { return doc[StrCast(doc.layoutKey, 'layout')]; } export function LayoutFieldKey(doc: Doc): string { - return StrCast(Doc.Layout(doc).layout).split("'")[1]; + return StrCast(Doc.Layout(doc)[StrCast(doc.layoutKey, 'layout')]).split("'")[1]; // bcz: TODO check on this . used to always reference 'layout', now it uses the layout speicfied by the current layoutKey } export function NativeAspect(doc: Doc, dataDoc?: Doc, useDim?: boolean) { return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1); @@ -1222,9 +1222,10 @@ export namespace Doc { return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeWidth'], useWidth ? doc[WidthSym]() : 0)); } export function NativeHeight(doc?: Doc, dataDoc?: Doc, useHeight?: boolean) { - const dheight = doc ? NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeHeight'], useHeight ? doc[HeightSym]() : 0) : 0; - const nheight = doc ? (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[HeightSym]()) / doc[WidthSym]() : 0; - return !doc ? 0 : NumCast(doc._nativeHeight, nheight || dheight); + if (!doc) return 0; + const nheight = (Doc.NativeWidth(doc, dataDoc, useHeight) * doc[HeightSym]()) / doc[WidthSym](); + const dheight = NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + '-nativeHeight'], useHeight ? doc[HeightSym]() : 0); + return NumCast(doc._nativeHeight, nheight || dheight); } export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) { doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '-nativeWidth'] = width; -- cgit v1.2.3-70-g09d2