From 1e60b99195bc6748bbad53d173a8a2525216d683 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 18 Mar 2022 08:29:55 -0400 Subject: fixed vertical resizing of web and pdf to not jump after sidebar panel is resized --- src/client/views/nodes/WebBox.tsx | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 7ff47107e..7f314bddc 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -590,10 +590,12 @@ export class WebBox extends ViewBoxAnnotatableComponent= 1) { this.layoutDoc.nativeWidth = nativeWidth * ratio; + this.layoutDoc.nativeHeight = nativeHeight * (1 + ratio); onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]); this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; } -- cgit v1.2.3-70-g09d2 From 70cd320fb02993b2abb17dcfb2a3fd1dfefabb36 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 23 Mar 2022 18:30:59 -0400 Subject: adjsuted pdfBox and WebBox to resize better without glitches when using the annotation sidebar. changed so that when fitWidth is set anything can be resized vertically - causes artifacts for videoBoxes. --- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 8 +++----- src/client/views/nodes/WebBox.tsx | 7 +++---- src/fields/Doc.ts | 7 ++++++- 4 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d0b5bfe46..39591e417 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -339,7 +339,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P } let actualdW = Math.max(width + (dW * scale), 20); let actualdH = Math.max(height + (dH * scale), 20); - const fixedAspect = (nwidth && nheight); + const fixedAspect = (nwidth && nheight && !doc._fitWidth); if (fixedAspect) { if ((Math.abs(dW) > Math.abs(dH) && (!dragBottom || !modifyNativeDim)) || dragRight) { if (dragRight && modifyNativeDim) { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index fa23dfbe8..a2e7d2aa3 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -141,12 +141,10 @@ export class PDFBox extends ViewBoxAnnotatableComponent { const localDelta = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformDirection(delta[0], delta[1]); const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); - const nativeHeight = NumCast(this.layoutDoc[this.fieldKey + "-nativeHeight"]); const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); const ratio = (curNativeWidth + (onButton ? 1 : -1) * localDelta[0] / (this.props.scaling?.() || 1)) / nativeWidth; if (ratio >= 1) { this.layoutDoc.nativeWidth = nativeWidth * ratio; - this.layoutDoc.nativeHeight = nativeHeight * (1 + ratio); onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]); this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; } @@ -227,8 +225,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent; } sidebarWidth = () => !this.SidebarShown ? 0 : - this._previewWidth ? PDFBox.openSidebarWidth : - (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth) + PDFBox.sidebarResizerWidth + (this._previewWidth ? PDFBox.openSidebarWidth : + (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth)) specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; @@ -264,7 +262,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent
this.sidebarBtnDown(e, false)} />
!this.SidebarShown ? 0 : - this._previewWidth ? WebBox.openSidebarWidth : - (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / - NumCast(this.layoutDoc.nativeWidth) + WebBox.sidebarResizerWidth + (this._previewWidth ? WebBox.openSidebarWidth : + (NumCast(this.layoutDoc.nativeWidth) - Doc.NativeWidth(this.dataDoc)) * this.props.PanelWidth() / NumCast(this.layoutDoc.nativeWidth)) @computed get content() { const interactive = !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.isContentActive() && this.props.pointerEvents !== "none" && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting; @@ -715,7 +714,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.sidebarBtnDown(e, false)} />
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 1253cf9c7..c932259de 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -346,6 +346,7 @@ export namespace Doc { return GetT(doc, "system", "boolean", true); } export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) { + if (key.startsWith("_")) key = key.substring(1); const hasProto = doc.proto instanceof Doc; const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1; const onProto = hasProto && Object.getOwnPropertyNames(doc.proto).indexOf(key) !== -1; @@ -962,7 +963,11 @@ export namespace Doc { return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1); } export function NativeWidth(doc?: Doc, dataDoc?: Doc, useWidth?: boolean) { 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) { return !doc ? 0 : NumCast(doc._nativeHeight, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + "-nativeHeight"], useHeight ? doc[HeightSym]() : 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); + } export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) { doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + "-nativeWidth"] = width; } export function SetNativeHeight(doc: Doc, height: number | undefined, fieldKey?: string) { doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + "-nativeHeight"] = height; } -- cgit v1.2.3-70-g09d2 From d21354fefc9f5b343e51c4db67e0bae7d0c187ee Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 24 Mar 2022 10:06:14 -0400 Subject: fixing data_url uploading to have a no suffix option. --- src/client/views/PropertiesButtons.tsx | 4 ++-- src/client/views/nodes/VideoBox.tsx | 7 +++++++ src/client/views/nodes/WebBox.tsx | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index dd6448654..24857d8ee 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -102,9 +102,9 @@ export class PropertiesButtons extends React.Component<{}, {}> { else { document.body.focus(); // so that we can access the clipboard without an error setTimeout(() => - pasteImageBitmap((data: any, error: any) => { + pasteImageBitmap((data_url: any, error: any) => { error && console.log(error); - data && VideoBox.convertDataUri(data, doc[Id] + "-thumb-frozen", true).then( + data_url && VideoBox.convertDataUri(data_url, doc[Id] + "-thumb-frozen", true).then( returnedfilename => doc["thumb-frozen"] = new ImageField(returnedfilename)); })); } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 33fdc4935..5019d5691 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -252,6 +252,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent { - VideoBox.convertDataUri(dataUrl, this.layoutDoc[Id] + "-thumb" + (new Date()).getTime(), true).then( + ((data_url: any) => { + VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-thumb" + (new Date()).getTime(), true).then( returnedfilename => setTimeout(action(() => this.layoutDoc.thumb = new ImageField(returnedfilename)), 500)); }) .catch(function (error: any) { -- cgit v1.2.3-70-g09d2 From c534619229b0f1b7d1ef5606d76f6e4829743379 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 24 Mar 2022 10:23:53 -0400 Subject: fixed scroll location of webpages when activated for first time. --- src/client/views/nodes/WebBox.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index e6acddf23..3e3a6cfa5 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -103,6 +103,14 @@ export class WebBox extends ViewBoxAnnotatableComponent { + if (!this._outerRef.current || this._outerRef.current.scrollHeight < pos) { + setTimeout(() => this.setScrollPos(pos), 250); + } else { + this._outerRef.current.scrollTop = pos; + this._initialScroll = undefined; + } + } async componentDidMount() { this.props.setContentView?.(this); // this tells the DocumentView that this WebBox is the "content" of the document. this allows the DocumentView to call WebBox relevant methods to configure the UI (eg, show back/forward buttons) @@ -118,11 +126,8 @@ export class WebBox extends ViewBoxAnnotatableComponent { this._scrollHeight = Math.max(this.scrollHeight, this._iframe?.contentDocument?.body.scrollHeight || 0); - if (this._initialScroll !== undefined && this._outerRef.current) { - setTimeout(() => { - this._outerRef.current!.scrollTop = this._initialScroll!; - this._initialScroll = undefined; - }); + if (this._initialScroll !== undefined) { + this.setScrollPos(this._initialScroll); } })); } else if (!this.props.isContentActive() && -- cgit v1.2.3-70-g09d2 From af37e51657913a4f1cc1536f7d7ad9f991d4dc32 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 24 Mar 2022 11:34:53 -0400 Subject: fixes for webbox scroll bars and resizer divider to show up properly --- src/client/views/nodes/WebBox.scss | 10 ++++++++-- src/client/views/nodes/WebBox.tsx | 15 ++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index 7dc970496..9d8825ad1 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -5,10 +5,16 @@ height: 100%; position: relative; display: flex; - .webBox-background { + .webBox-sideResizer { + position: absolute; width: 100%; height: 100%; cursor: ew-resize; + background: yellow; + } + .webBox-background { + width: 100%; + height: 100%; background: lightGray; } @@ -193,7 +199,7 @@ } div.webBox-outerContent::-webkit-scrollbar-thumb { - display: none; + cursor: nw-resize; } } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index e6acddf23..495f6a7ba 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -666,7 +666,7 @@ export class WebBox extends ViewBoxAnnotatableComponent) => this._searchString = e.currentTarget.value; showInfo = action((anno: Opt) => this._overlayAnnoInfo = anno); setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => this._setPreviewCursor = func; - panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); + panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth; // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0); panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document); scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop)); anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; @@ -711,10 +711,9 @@ export class WebBox extends ViewBoxAnnotatableComponent -
this.sidebarBtnDown(e, false)} /> +
@@ -751,6 +750,12 @@ export class WebBox extends ViewBoxAnnotatableComponent}
+
this.sidebarBtnDown(e, false)} /> Date: Fri, 25 Mar 2022 12:10:50 -0400 Subject: fixed annotations on web pages to be scaled to the correct location. --- src/client/views/nodes/WebBox.tsx | 25 +++++++++++++------------ src/client/views/pdf/PDFViewer.tsx | 11 +++++++---- 2 files changed, 20 insertions(+), 16 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index eca0138a0..c12059943 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -742,18 +742,19 @@ export class WebBox extends ViewBoxAnnotatableComponent
{!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) : - } +
+
}
{ {this.overlayInfo} {this.standinViews} {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) : - this.props.addDocument!(doc)} - finishMarquee={this.finishMarquee} docView={this.props.docViewPath().lastElement()} - getPageFromScroll={this.getPageFromScroll} + finishMarquee={this.finishMarquee} savedAnnotations={this._savedAnnotations} - annotationLayer={this._annotationLayer.current} mainCont={this._mainCont.current} />} + annotationLayer={this._annotationLayer.current} + mainCont={this._mainCont.current} />}
; } -- cgit v1.2.3-70-g09d2 From ef63a072a586f51e8fa51b4684987491287540b2 Mon Sep 17 00:00:00 2001 From: Naafiyan Ahmed Date: Thu, 7 Apr 2022 17:21:01 -0400 Subject: added grouping and write mode vs pen mode --- src/client/util/CurrentUserUtils.ts | 4 +- src/client/views/GestureOverlay.tsx | 5 +- .../views/collections/CollectionDockingView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 12 +-- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- src/client/views/nodes/button/FontIconBox.tsx | 112 ++++++++++----------- src/client/views/pdf/PDFViewer.tsx | 2 +- src/fields/InkField.ts | 3 +- webpack.config.js | 2 +- 14 files changed, 77 insertions(+), 79 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 6cab8c100..f08f13bbc 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1010,8 +1010,8 @@ export class CurrentUserUtils { static inkTools(doc: Doc) { const tools: Button[] = [ - { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen", click: 'setActiveInkTool("pen", _readOnly_)' }, - { title: "Mode", toolTip: "Mode (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen", click: 'setActiveInkTool("write", _readOnly_)' }, + { title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", click: 'setActiveInkTool("pen", _readOnly_)' }, + { title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", click: 'setActiveInkTool("write", _readOnly_)' }, { title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", click: 'setActiveInkTool("eraser", _readOnly_)' }, // { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", click: 'setActiveInkTool("highlighter")' }, { title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", click: 'setActiveInkTool("circle", _readOnly_)' }, diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 87b006a93..53b360e60 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -491,7 +491,10 @@ export class GestureOverlay extends Touchable { @action onPointerDown = (e: React.PointerEvent) => { - if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { + if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { + CurrentUserUtils.SelectedTool = InkTool.Write; + } this._points.push({ X: e.clientX, Y: e.clientY }); setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction); // if (CurrentUserUtils.SelectedTool === InkTool.Highlighter) SetActiveInkColor("rgba(245, 230, 95, 0.75)"); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 9e8374605..c9f55a7bd 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -358,7 +358,7 @@ export class CollectionDockingView extends CollectionSubView() { } } if (!e.nativeEvent.cancelBubble && !InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && - ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { e.stopPropagation(); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a694ca2b3..40164313c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -468,6 +468,8 @@ export class CollectionFreeFormView extends CollectionSubView e.preventDefault()} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7092b335c..2e822bb6a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -517,7 +517,7 @@ export class DocumentViewInternal extends DocComponent { // continue if the event hasn't been canceled AND we are using a mouse or this has an onClick or onDragStart function (meaning it is a button document) - if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) { + if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool))) { if (!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { e.stopPropagation(); if (SelectionManager.IsSelected(this.props.DocumentView(), true) && this.props.Document._viewType !== CollectionViewType.Docking) e.preventDefault(); // goldenlayout needs to be able to move its tabs, so can't preventDefault for it @@ -550,7 +550,7 @@ export class DocumentViewInternal extends DocComponent { if (e.cancelBubble) return; - if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) return; + if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool))) return; if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0a4168698..a8da22b61 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -322,7 +322,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent; } marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index aa2130af5..9bf7c2e8c 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -471,7 +471,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 33fdc4935..a5b8967c4 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -549,7 +549,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 7ff47107e..54c49ecad 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -529,7 +529,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index fc0cc87ca..7f3a667a9 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -13,6 +13,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields import { WebField } from '../../../../fields/URLField'; import { aggregateBounds, Utils } from '../../../../Utils'; import { DocumentType } from '../../../documents/DocumentTypes'; +import { CurrentUserUtils } from '../../../util/CurrentUserUtils'; import { DocumentManager } from '../../../util/DocumentManager'; import { ScriptingGlobals } from "../../../util/ScriptingGlobals"; import { SelectionManager } from '../../../util/SelectionManager'; @@ -717,64 +718,56 @@ ScriptingGlobals.add(function setActiveInkTool(tool: string, checkResult?: boole // easy way without backing up to the server // - CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { - const selected = ffView.unprocessedDocs; - ffView._marqueeViewRef.current?.getCollection(ffView.unprocessedDocs, undefined, [], true); - // loop through selected an get the bound - const bounds: { x: number, y: number, width?: number, height?: number }[] = [] - - selected.map(action(d => { - const x = NumCast(d.x); - const y = NumCast(d.y); - const width = d[WidthSym](); - const height = d[HeightSym](); - bounds.push({x, y, width, height}); - })) - - const aggregBounds = aggregateBounds(bounds, 0, 0); - const marqViewRef = ffView._marqueeViewRef.current; - - // set the vals for bounds in marqueeView - if (marqViewRef) { - marqViewRef._downX = aggregBounds.x; - marqViewRef._downY = aggregBounds.y; - marqViewRef._lastX = aggregBounds.r; - marqViewRef._lastY = aggregBounds.b; - } - - selected.map(action(d => { - const dx = NumCast(d.x); - const dy = NumCast(d.y); - delete d.x; - delete d.y; - delete d.activeFrame; - delete d._timecodeToShow; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection - delete d._timecodeToHide; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection - // TODO: nda - actually calc the bounds - // get the bounds - // d.x = dx - aggregBounds.x; - // d.y = dy - aggregBounds.y; + if (CurrentUserUtils.SelectedTool === InkTool.Write) { + CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { + const selected = ffView.unprocessedDocs; + // loop through selected an get the bound + const bounds: { x: number, y: number, width?: number, height?: number }[] = [] - // d.x = dx - aggregBounds.x ; - // d.y = dy; - if (marqViewRef?.Bounds) { - d.x = dx - marqViewRef.Bounds.left - marqViewRef.Bounds?.width / 2; - d.y = dy - marqViewRef.Bounds.top - marqViewRef.Bounds.height / 2; - } - console.log(d[DataSym], d.x, d.y) - return d; - })); - ffView.props.removeDocument?.(selected); - // TODO: nda - this is the code to actually get a new grouped collection - // const newCollection = ffView._marqueeViewRef.current?.getCollection(ffView.unprocessedDocs, undefined, [], true); - const newCollection = marqViewRef?.getCollection(selected, undefined, [], true); - console.log("newcoll:", newCollection?.[DataSym]); - - // nda - bug: when deleting a stroke before leaving writing mode, delete the stroke from unprocessed ink docs - newCollection && ffView.props.addDocument?.(newCollection); - ffView.unprocessedDocs = []; - }); - + selected.map(action(d => { + const x = NumCast(d.x); + const y = NumCast(d.y); + const width = d[WidthSym](); + const height = d[HeightSym](); + bounds.push({x, y, width, height}); + })) + + const aggregBounds = aggregateBounds(bounds, 0, 0); + const marqViewRef = ffView._marqueeViewRef.current; + + // set the vals for bounds in marqueeView + if (marqViewRef) { + marqViewRef._downX = aggregBounds.x; + marqViewRef._downY = aggregBounds.y; + marqViewRef._lastX = aggregBounds.r; + marqViewRef._lastY = aggregBounds.b; + } + + selected.map(action(d => { + const dx = NumCast(d.x); + const dy = NumCast(d.y); + delete d.x; + delete d.y; + delete d.activeFrame; + delete d._timecodeToShow; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection + delete d._timecodeToHide; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection + // TODO: nda - actually calc the bounds + // calculate pos based on bounds + if (marqViewRef?.Bounds) { + d.x = dx - marqViewRef.Bounds.left - marqViewRef.Bounds.width / 2; + d.y = dy - marqViewRef.Bounds.top - marqViewRef.Bounds.height / 2; + } + return d; + })); + ffView.props.removeDocument?.(selected); + // TODO: nda - this is the code to actually get a new grouped collection + const newCollection = marqViewRef?.getCollection(selected, undefined, [], true); + + // nda - bug: when deleting a stroke before leaving writing mode, delete the stroke from unprocessed ink docs + newCollection && ffView.props.addDocument?.(newCollection); + ffView.unprocessedDocs = []; + }); + } CollectionFreeFormView.collectionsWithUnprocessedInk.clear(); if (checkResult) { @@ -793,8 +786,9 @@ ScriptingGlobals.add(function setActiveInkTool(tool: string, checkResult?: boole if (Doc.UserDoc().activeInkTool === tool && !GestureOverlay.Instance.InkShape) { Doc.UserDoc().activeInkTool = InkTool.None; } else if (tool == "write") { - console.log("write mode selected - create groupDoc here!") - // + console.log("write mode selected - create groupDoc here!", tool) + Doc.UserDoc().activeInkTool = tool; + GestureOverlay.Instance.InkShape = ""; } else { Doc.UserDoc().activeInkTool = tool; GestureOverlay.Instance.InkShape = ""; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 1856c5353..37fbd7a1d 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -371,7 +371,7 @@ export class PDFViewer extends React.Component { if ((e.button !== 0 || e.altKey) && this.props.isContentActive(true)) { this._setPreviewCursor?.(e.clientX, e.clientY, true, false); } - if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool)) { this.props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts index 31024e805..c34e8f93d 100644 --- a/src/fields/InkField.ts +++ b/src/fields/InkField.ts @@ -11,7 +11,8 @@ export enum InkTool { Pen = "pen", Highlighter = "highlighter", Eraser = "eraser", - Stamp = "stamp" + Stamp = "stamp", + Write = "write" } diff --git a/webpack.config.js b/webpack.config.js index 3fd00bcf3..5a954db19 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -49,7 +49,7 @@ module.exports = { repl: ["./src/debug/Repl.tsx", 'webpack-hot-middleware/client?reload=true'], test: ["./src/debug/Test.tsx", 'webpack-hot-middleware/client?reload=true'], inkControls: ["./src/mobile/InkControls.tsx", 'webpack-hot-middleware/client?reload=true'], - mobileInterface: ["./src/mobile/MobileMain.tsx", 'webpack-hot-middleware/client?reload=true'], + mobileInterface: ["./src/client/views/Main.tsx", 'webpack-hot-middleware/client?reload=true'], }, devtool: "source-map", output: { -- cgit v1.2.3-70-g09d2 From 6c7101d4f69dd79a83a48d04356748213c38a435 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 11 Apr 2022 13:31:33 -0400 Subject: making layout icons work better. --- src/client/documents/Documents.ts | 4 ++- src/client/util/CurrentUserUtils.ts | 15 +++++--- src/client/util/DragManager.ts | 6 ++-- src/client/views/DocumentDecorations.tsx | 20 ++++++++--- src/client/views/InkingStroke.tsx | 6 +++- src/client/views/StyleProvider.tsx | 7 ++-- .../views/collections/CollectionCarouselView.tsx | 4 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 40 ++++++++++++++++++++++ .../collectionFreeForm/MarqueeView.scss | 1 + src/client/views/nodes/DocumentView.tsx | 7 ++-- src/client/views/nodes/ImageBox.tsx | 6 ++-- src/client/views/nodes/LabelBigText.js | 33 +++++++++++++----- src/client/views/nodes/LabelBox.tsx | 5 +-- src/client/views/nodes/WebBox.tsx | 4 +-- src/fields/Doc.ts | 2 +- 15 files changed, 123 insertions(+), 37 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index bb60586eb..652f8e7e0 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -139,6 +139,8 @@ export class DocumentOptions { _itemIndex?: number; // which item index the carousel viewer is showing _showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts _singleLine?: boolean; // whether text document is restricted to a single line (carriage returns make new document) + _minFontSize?: number; // minimum font size for labelBoxes + _maxFontSize?: number; // maximum font size for labelBoxes _columnWidth?: number; _columnsHideIfEmpty?: boolean; // whether stacking view column headings should be hidden _fontSize?: string; @@ -441,7 +443,7 @@ export namespace Docs { }], [DocumentType.LABEL, { layout: { view: LabelBox, dataField: defaultDataKey }, - options: { links: "@links(self)" } + options: { links: "@links(self)", _singleLine: true } }], [DocumentType.EQUATION, { layout: { view: EquationBox, dataField: defaultDataKey }, diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index af731ce9f..bc4dbcb2e 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -9,7 +9,7 @@ import { RichTextField } from "../../fields/RichTextField"; import { listSpec } from "../../fields/Schema"; import { ComputedField, ScriptField } from "../../fields/ScriptField"; import { BoolCast, Cast, DateCast, NumCast, PromiseValue, StrCast } from "../../fields/Types"; -import { nullAudio } from "../../fields/URLField"; +import { ImageField, nullAudio } from "../../fields/URLField"; import { SharingPermissions } from "../../fields/util"; import { Utils } from "../../Utils"; import { DocServer } from "../DocServer"; @@ -292,7 +292,7 @@ export class CurrentUserUtils { if (doc["template-icon-view"] === undefined) { const iconView = Docs.Create.LabelDocument({ title: "icon", textTransform: "unset", letterSpacing: "unset", layout: LabelBox.LayoutString("title"), _backgroundColor: "dimgray", - _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true }); // Docs.Create.TextDocument("", { // title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }) @@ -304,7 +304,8 @@ export class CurrentUserUtils { if (doc["template-icon-view-rtf"] === undefined) { const iconRtfView = Docs.Create.LabelDocument({ title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset", layout: LabelBox.LayoutString("text"), - _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + _singleLine: false, _minFontSize: 18, _maxFontSize: 24, + _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true }); iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF); doc["template-icon-view-rtf"] = new PrefetchProxy(iconRtfView); @@ -319,14 +320,18 @@ export class CurrentUserUtils { } if (doc["template-icon-view-img"] === undefined) { const iconImageView = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { - title: "data", _width: 50, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + title: "data", _width: 50, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true }); iconImageView.isTemplateDoc = makeTemplate(iconImageView, true, "icon_" + DocumentType.IMG); doc["template-icon-view-img"] = new PrefetchProxy(iconImageView); } if (doc["template-icon-view-col"] === undefined) { - const iconColView = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, onDoubleClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true }); + const iconColView = Docs.Create.ImageDocument("", { title: "icon", _width: 180 / 4, _height: 135 / 4, onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true }); iconColView.isTemplateDoc = makeTemplate(iconColView, true, "icon_" + DocumentType.COL); + const proto = iconColView.proto as Doc; + proto["icon-nativeWidth"] = 180 / 4; + proto["icon-nativeHeight"] = 135 / 4; + proto.icon = new ImageField("http://www.cs.brown.edu/~bcz/noImage.png"); doc["template-icon-view-col"] = new PrefetchProxy(iconColView); } if (doc["template-icons"] === undefined) { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 411fc6d11..d6d04db9a 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -380,8 +380,8 @@ export namespace DragManager { } } const rect = ele.getBoundingClientRect(); - const scaleX = rect.width / ele.offsetWidth; - const scaleY = ele.offsetHeight ? rect.height / ele.offsetHeight : scaleX; + const scaleX = rect.width / (ele.offsetWidth || rect.width); + const scaleY = ele.offsetHeight ? rect.height / (ele.offsetHeight || rect.height) : scaleX; elesCont.left = Math.min(rect.left, elesCont.left); elesCont.top = Math.min(rect.top, elesCont.top); @@ -424,7 +424,7 @@ export namespace DragManager { const hideDragShowOriginalElements = (hide: boolean) => { dragLabel.style.display = hide ? "" : "none"; - !hide && dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); + //!hide && dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); eles.forEach(ele => ele.hidden = hide); }; options?.hideSource && hideDragShowOriginalElements(true); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d7ead713a..1487d5bb0 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -144,10 +144,17 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P return true; } + _iconifyTimeout: NodeJS.Timeout | undefined; onCloseClick = () => { - const selected = SelectionManager.Views().slice(); - SelectionManager.DeselectAll(); - selected.map(dv => dv.props.removeDocument?.(dv.props.Document)); + const views = SelectionManager.Views().slice().filter(v => v); + const icons = this._iconifyTimeout ? views : views.filter(view => view.rootDoc.layoutKey === "layout_icon"); + const others = this._iconifyTimeout ? [] : views.filter(view => view.rootDoc.layoutKey !== "layout_icon"); + icons.forEach(iconView => iconView.props.removeDocument?.(iconView.props.Document)); + others.forEach(dv => dv.iconify()); + others.length && (this._iconifyTimeout = setTimeout(() => { + views.forEach(view => SelectionManager.DeselectView(view)); + this._iconifyTimeout = undefined; + }, 1000)); } onMaximizeDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, () => { @@ -171,7 +178,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P } else if (e.altKey) { // open same document in new tab CollectionDockingView.ToggleSplit(selectedDocs[0].props.Document, "right"); } else { - LightboxView.SetLightboxDoc(selectedDocs[0].props.Document, undefined, selectedDocs.slice(1).map(view => view.props.Document)); + var openDoc = selectedDocs[0].props.Document; + if (openDoc.layoutKey === "layout_icon") { + openDoc = DocListCast(openDoc.aliases).find(alias => !alias.context) ?? Doc.MakeAlias(openDoc); + Doc.deiconifyView(openDoc); + } + LightboxView.SetLightboxDoc(openDoc, undefined, selectedDocs.slice(1).map(view => view.props.Document)); } } SelectionManager.DeselectAll(); diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 06671961d..5e589fdea 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -70,7 +70,11 @@ export class InkingStroke extends ViewBoxBaseComponent() { // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc) - screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1); + screenToLocal = () => { + console.log("Scaling = " + this.props.scaling?.()) + console.log("Stolocal = " + this.props.ScreenToLocalTransform().Scale) + return this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1); + } getAnchor = () => { console.log(document.activeElement); diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 649ee8394..739670ecf 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -117,7 +117,10 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?.[fieldKey + "backgroundColor"], StrCast(doc?._backgroundColor, isCaption ? "rgba(0,0,0,0.4)" : "")); + let docColor: Opt = + StrCast(doc?.[fieldKey + "backgroundColor"], + StrCast(doc?._backgroundColor, + StrCast(props?.Document.backgroundColor, isCaption ? "rgba(0,0,0,0.4)" : ""))); switch (doc?.type) { case DocumentType.PRESELEMENT: docColor = docColor || (darkScheme() ? "" : ""); break; case DocumentType.PRES: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE); break; @@ -127,7 +130,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt
- { + if (this.clicks) { + console.log("UPDATE ICON"); + } + this.clicks++; + this.props.docViewPath().lastElement().ContentDiv!.style.width = (this.layoutDoc[WidthSym]()).toString(); + this.props.docViewPath().lastElement().ContentDiv!.style.height = (this.layoutDoc[HeightSym]()).toString(); + var htmlString = this._mainCont && new XMLSerializer().serializeToString(this.props.docViewPath().lastElement().ContentDiv!); + this.props.docViewPath().lastElement().ContentDiv!.style.width = ""; + this.props.docViewPath().lastElement().ContentDiv!.style.height = ""; + const nativeWidth = this.layoutDoc[WidthSym](); + const nativeHeight = this.layoutDoc[HeightSym](); + + CreateImage( + "", + document.styleSheets, + htmlString?.replace(/"marqueeView"/g, '"marqueeView marqueeView2"'), + nativeWidth, + nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(), + NumCast(this.layoutDoc._scrollTop) + ).then + ((data_url: any) => { + VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true).then( + returnedfilename => setTimeout(action(() => { + + this.dataDoc.icon = new ImageField(returnedfilename); + this.dataDoc["icon-nativeWidth"] = nativeWidth; + this.dataDoc["icon-nativeHeight"] = nativeHeight; + }), 500)); + }) + .catch(function (error: any) { + console.error('oops, something went wrong!', error); + }); + } + componentWillUnmount() { Object.values(this._disposers).forEach(disposer => disposer?.()); this._marqueeRef.current?.removeEventListener("dashDragAutoScroll", this.onDragAutoScroll as any); @@ -1476,6 +1515,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" }); !Doc.UserDoc().noviceMode && Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); appearanceItems.push({ description: `${this.fitToContent ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); + appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: "compress-arrows-alt" }); this.props.ContainingCollectionView && appearanceItems.push({ description: "Ungroup collection", event: this.promoteCollection, icon: "table" }); !Doc.UserDoc().noviceMode ? appearanceItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }) : null; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss index 62510ce9d..41e4d6b6a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss @@ -10,6 +10,7 @@ user-select: none; } + .marqueeView:focus-within { overflow: hidden; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 103c3624d..185eafa4a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -80,6 +80,7 @@ export type DocAfterFocusFunc = (notFocused: boolean) => Promise export type DocFocusFunc = (doc: Doc, options?: DocFocusOptions) => void; export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; export interface DocComponentView { + updateIcon?: () => void; // updates the icon representation of the document getAnchor?: () => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) scrollFocus?: (doc: Doc, smooth: boolean) => Opt; // returns the duration of the focus setViewSpec?: (anchor: Doc, preview: boolean) => void; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document @@ -1118,6 +1119,7 @@ export class DocumentViewInternal extends DocComponent !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document)} onPointerLeave={e => !hasDescendantTarget(e.nativeEvent.x, e.nativeEvent.y, this.ContentDiv) && Doc.UnBrushDoc(this.props.Document)} style={{ + display: "inline", borderRadius: this.borderRounding, pointerEvents: this.pointerEvents, outline: highlighting && !this.borderRounding ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : "solid 0px", @@ -1233,6 +1235,7 @@ export class DocumentView extends React.Component { } public iconify() { + this.ComponentView?.updateIcon?.(); const layoutKey = Cast(this.Document.layoutKey, "string", null); if (layoutKey !== "layout_icon") { this.switchViews(true, "icon"); @@ -1332,8 +1335,8 @@ export function deiconifyViewFunc(documentView: DocumentView) { } ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) { documentView.iconify(); -} -); + documentView.select(false); +}); ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) { if (dv.Document.layoutKey === "layout_" + detailLayoutKeySuffix) dv.switchViews(false, "layout"); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 17f95c1cc..fb9e86487 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -73,7 +73,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent this._curSuffix = forceFull ? "_o" : scrSize < 100 ? "_s" : scrSize < 400 ? "_m" : scrSize < 800 || !selected ? "_l" : "_o", + ({ forceFull, scrSize, selected }) => this._curSuffix = this.fieldKey === "icon" ? "_m" : forceFull ? "_o" : scrSize < 100 ? "_s" : scrSize < 400 ? "_m" : scrSize < 800 || !selected ? "_l" : "_o", { fireImmediately: true, delay: 1000 }); this._disposers.path = reaction(() => ({ nativeSize: this.nativeSize, width: this.layoutDoc[WidthSym]() }), ({ nativeSize, width }) => { @@ -245,8 +245,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent options.maximumFontSize) { + if (fontSize < options.minimumFontSize) { + parentStyle.display = "flex"; + parentStyle.alignItems = "center"; + style.whiteSpace = "pre-wrap"; + style.textAlign = "center"; + style.visibility = ""; + style.fontSize = "18px"; + style.lineHeight = "20px"; + style.top = ""; + style.left = ""; + style.margin = ""; + return element; + } + if (options.maximumFontSize && fontSize > options.maximumFontSize) { fontSize = options.maximumFontSize; lineHeight = fontSize / options.fontSizeFactor; } diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 0015f0b71..c689d9f40 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; -import { Cast, StrCast } from '../../../fields/Types'; +import { Cast, StrCast, NumCast } from '../../../fields/Types'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; @@ -100,7 +100,8 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro BigText(r, { rotateText: null, fontSizeFactor: 1, - maximumFontSize: null, + minimumFontSize: NumCast(this.layoutDoc._minFontSize), + maximumFontSize: NumCast(this.layoutDoc._maxFontSize), limitingDimension: "both", horizontalAlign: "center", verticalAlign: "center", diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c12059943..0fd193977 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -130,8 +130,8 @@ export class WebBox extends ViewBoxAnnotatableComponent Date: Mon, 25 Apr 2022 20:20:48 -0400 Subject: changed freeformview's with engines to not allow children to be edited using setHeight prop since engine layouts are temporary and shouldn't edit the doc. fixed tags to work with pivot view. cleaned up pile views to be less hacky.. --- src/client/documents/Documents.ts | 27 +++++++++++++--------- src/client/views/MainView.tsx | 1 + src/client/views/SidebarAnnos.tsx | 2 +- .../views/collections/CollectionPileView.tsx | 4 ++-- .../views/collections/CollectionStackingView.tsx | 6 ++--- src/client/views/collections/CollectionSubView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/TreeView.tsx | 1 + .../CollectionFreeFormLayoutEngines.tsx | 26 +++++++++++++-------- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +++- .../views/nodes/CollectionFreeFormDocumentView.tsx | 5 +--- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 17 +++++++------- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 1 + src/client/views/nodes/WebBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 2 +- src/fields/Doc.ts | 2 +- 19 files changed, 62 insertions(+), 48 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 49e53a214..a19530c92 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -14,7 +14,7 @@ import { Cast, NumCast, StrCast } from "../../fields/Types"; import { AudioField, ImageField, MapField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField"; import { SharingPermissions } from "../../fields/util"; import { Upload } from "../../server/SharedMediaTypes"; -import { OmitKeys, Utils } from "../../Utils"; +import { OmitKeys, Utils, aggregateBounds } from "../../Utils"; import { YoutubeBox } from "../apis/youtube/YoutubeBox"; import { DocServer } from "../DocServer"; import { Networking } from "../Network"; @@ -1352,26 +1352,31 @@ export namespace DocUtils { if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") doc.deiconifyLayout = layoutKey.replace("layout_", ""); } - export function pileup(docList: Doc[], x?: number, y?: number, create: boolean = true) { + export function pileup(docList: Doc[], x?: number, y?: number, size: number = 55, create: boolean = true) { let w = 0, h = 0; runInAction(() => { docList.forEach(d => { DocUtils.iconify(d); - w = Math.max(d[WidthSym](), w); - h = Math.max(d[HeightSym](), h); + w = Math.max(NumCast(d._width), w); + h = Math.max(NumCast(d._height), h); }); - h = Math.max(h, w * 4 / 3); // converting to an icon does not update the height right away. so this is a fallback hack to try to do something reasonable docList.forEach((d, i) => { - d.x = Math.cos(Math.PI * 2 * i / docList.length) * 10 - w / 2; - d.y = Math.sin(Math.PI * 2 * i / docList.length) * 10 - h / 2; + d.x = Math.cos(Math.PI * 2 * i / docList.length) * size; + d.y = Math.sin(Math.PI * 2 * i / docList.length) * size; + d._timecodeToShow = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection + }); + const aggBounds = aggregateBounds(docList.map(d => ({ x: NumCast(d.x), y: NumCast(d.y), width: NumCast(d._width), height: NumCast(d._height) })), 0, 0); + docList.forEach((d, i) => { + d.x = NumCast(d.x) - ((aggBounds.r + aggBounds.x) / 2); + d.y = NumCast(d.y) - ((aggBounds.b + aggBounds.y) / 2); d._timecodeToShow = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection }); }); if (create) { - const newCollection = Docs.Create.PileDocument(docList, { title: "pileup", x: (x || 0) - 55, y: (y || 0) - 55, _width: 110, _height: 100, }); - newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - 55; - newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55; - newCollection._width = newCollection._height = 110; + const newCollection = Docs.Create.PileDocument(docList, { title: "pileup", x: (x || 0) - size, y: (y || 0) - size, _width: size * 2, _height: size * 2, }); + newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - size; + newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - size; + newCollection._width = newCollection._height = size * 2; newCollection._jitterRotation = 10; return newCollection; } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index a67cb3014..68b4710ed 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -297,6 +297,7 @@ export class MainView extends React.Component { searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} + suppressSetHeight={true} renderDepth={-1} />; } diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index fae385660..43a02d029 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -88,7 +88,7 @@ export class SidebarAnnos extends React.Component { removeDocument = (doc: Doc | Doc[]) => this.props.removeDocument(doc, this.sidebarKey); docFilters = () => [...StrListCast(this.props.layoutDoc._docFilters), ...StrListCast(this.props.layoutDoc[this.filtersKey])]; showTitle = () => "title"; - setHeightCallback = (height: number) => this.props.setHeight(height + this.filtersHeight()); + setHeightCallback = (height: number) => this.props.setHeight?.(height + this.filtersHeight()); render() { const renderTag = (tag: string) => { const active = StrListCast(this.props.rootDoc[this.filtersKey]).includes(`${tag}:${tag}:check`); diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 8832b0f4a..4489601db 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -74,13 +74,13 @@ export class CollectionPileView extends CollectionSubView() { this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2; this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize); this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize); - DocUtils.pileup(this.childDocs, undefined, undefined, false); + DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false); this.layoutDoc._panX = 0; this.layoutDoc._panY = -10; this.props.Document._pileLayoutEngine = 'pass'; } else { const defaultSize = 25; - !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 500); + !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 250); !this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5); if (this.layoutEngine() === 'pass') { this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - defaultSize / 2; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 8634ea139..509005b45 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -141,7 +141,7 @@ export class CollectionStackingView extends CollectionSubView this.layoutDoc._columnHeaders = new List() ); this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight, - autoHeight => autoHeight && this.props.setHeight(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), + autoHeight => autoHeight && this.props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), this.headerMargin + (this.isStackingView ? Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))) : this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0))))); @@ -408,7 +408,7 @@ export class CollectionStackingView extends CollectionSubView Number(getComputedStyle(r).height.replace("px", ""))))); if (!LightboxView.IsLightboxDocView(this.props.docViewPath())) { - this.props.setHeight(height); + this.props.setHeight?.(height); } } })); @@ -458,7 +458,7 @@ export class CollectionStackingView extends CollectionSubView { if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0); - this.props.setHeight(this.headerMargin + height); + this.props.setHeight?.(this.headerMargin + height); } })); this.observer.observe(ref); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 5bdd0c0ac..30e0adf24 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -453,7 +453,7 @@ export function CollectionSubView(moreProps?: X) { if (completed) completed(set); else { if (isFreeformView && generatedDocuments.length > 1) { - addDocument(DocUtils.pileup(generatedDocuments, options.x!, options.y!)!); + addDocument(DocUtils.pileup(generatedDocuments, options.x!, options.y!)!,); } else { generatedDocuments.forEach(addDocument); } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 76da96174..41970eb96 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -88,7 +88,7 @@ export class CollectionTreeView extends CollectionSubView p + Number(getComputedStyle(r).height.replace("px", "")), this.marginBot()); this.layoutDoc._autoHeightMargins = bodyHeight; - this.props.setHeight(bodyHeight + titleHeight); + this.props.setHeight?.(bodyHeight + titleHeight); } } unobserveHeight = (ref: any) => { diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 6213850d8..b9710b3f5 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -30,6 +30,7 @@ import { CollectionTreeView } from './CollectionTreeView'; import { CollectionView, CollectionViewType } from './CollectionView'; import "./TreeView.scss"; import React = require("react"); +import { KeyValueBox } from '../nodes/KeyValueBox'; export interface TreeViewProps { treeView: CollectionTreeView; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 598960af7..16c7df311 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -111,17 +111,17 @@ export function computerStarburstLayout( viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any ) { - const mustFit = pivotDoc[WidthSym]() !== panelDim[0]; + const mustFit = pivotDoc[WidthSym]() !== panelDim[0]; // if a panel size is set that's not the same as the pivot doc's size, then assume this is in a panel for a content fitting view (like a grid) in which case everything must be scaled to stay within the panel const docMap = new Map(); - const burstRadius = mustFit ? panelDim : [NumCast(pivotDoc._starburstRadius, panelDim[0]), NumCast(pivotDoc._starburstRadius, panelDim[1])]; - const docSize = mustFit ? panelDim[0] * .33 : 75; // assume a icon sized at 75 - const scaleDim = [burstRadius[0] + docSize, burstRadius[1] + docSize]; + const docSize = mustFit ? panelDim[0] * .33 : 75; // assume an icon sized at 75 + const burstRadius = mustFit ? panelDim : [NumCast(pivotDoc._starburstRadius, panelDim[0]) - docSize, NumCast(pivotDoc._starburstRadius, panelDim[1]) - docSize]; + const scaleDim = [burstRadius[0] * 2 + docSize, burstRadius[1] * 2 + docSize]; childPairs.forEach(({ layout, data }, i) => { - const docSize = layout.layoutKey === "layout_icon" ? mustFit ? panelDim[0] * .33 : 75 : 400; // assume a icon sized at 10750 + const docSize = layout.layoutKey === "layout_icon" ? (mustFit ? panelDim[0] * .33 : 75) : 400; // assume a icon sized at 75 const deg = i / childPairs.length * Math.PI * 2; docMap.set(layout[Id], { - x: Math.cos(deg) * (burstRadius[0] / 3) - docSize / 2, - y: Math.sin(deg) * (burstRadius[1] / 3) - docSize * layout[HeightSym]() / layout[WidthSym]() / 2, + x: Math.cos(deg) * burstRadius[0] - docSize / 2, + y: Math.sin(deg) * burstRadius[1] - docSize * layout[HeightSym]() / layout[WidthSym]() / 2, width: docSize,//layout[WidthSym](), height: docSize * layout[HeightSym]() / layout[WidthSym](), zIndex: NumCast(layout.zIndex), @@ -129,7 +129,7 @@ export function computerStarburstLayout( replica: "" }); }); - const divider = { type: "div", color: "transparent", x: -burstRadius[0] / 3, y: 0, width: 15, height: 15, payload: undefined }; + const divider = { type: "div", color: "transparent", x: -burstRadius[0], y: 0, width: 15, height: 15, payload: undefined }; return normalizeResults(scaleDim, 12, docMap, poolData, viewDefsToJSX, [], 0, [divider]); } @@ -267,7 +267,13 @@ export function computePivotLayout( }); const dividers = sortedPivotKeys.map((key, i) => - ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2, y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters })); + ({ + type: "div", color: "lightGray", + x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2, + y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, + height: maxColHeight, + payload: pivotColumnGroups.get(key)!.filters + })); groupNames.push(...dividers); return normalizeResults(panelDim, max_text, docMap, poolData, viewDefsToJSX, groupNames, 0, []); } @@ -404,7 +410,7 @@ function normalizeResults( const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds); const docEles = Array.from(docMap.entries()).map(ele => ele[1]); const aggBounds = aggregateBounds(extras.concat(grpEles.concat(docEles.map(de => ({ ...de, type: "doc", payload: "" })))).filter(e => e.zIndex !== -99), 0, 0); - aggBounds.r = Math.max(minWidth, aggBounds.r - aggBounds.x); + aggBounds.r = aggBounds.x + Math.max(minWidth, aggBounds.r - aggBounds.x); const wscale = panelDim[0] / (aggBounds.r - aggBounds.x); let scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] ? (panelDim[1]) / (aggBounds.b - aggBounds.y) : wscale; if (Number.isNaN(scale)) scale = 1; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index eaef1b49c..a14405a0b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1158,6 +1158,7 @@ export class CollectionFreeFormView extends CollectionSubView(); - switch (this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine)) { + switch (this.layoutEngine) { case "pass": return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) }; case "timeline": return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; case "pivot": return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) }; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 3e35039e3..6097425e1 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -17,9 +17,6 @@ import { StyleProp } from "../StyleProvider"; import "./CollectionFreeFormDocumentView.scss"; import { DocumentView, DocumentViewProps } from "./DocumentView"; import React = require("react"); -import { DocumentType } from "../../documents/DocumentTypes"; -import { collectionSchema } from "../../../fields/documentSchemas"; -import { CollectionViewType } from "../collections/CollectionView"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined; @@ -174,7 +171,7 @@ export class CollectionFreeFormDocumentView extends DocComponent boolean, select: (ctrl: boolean) => void, scaling?: () => number, - setHeight: (height: number) => void, + setHeight?: (height: number) => void, layoutKey: string, }> { @computed get layout(): string { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 504a3afb6..20eabe6a9 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -114,6 +114,7 @@ export interface DocumentViewSharedProps { fitContentsToDoc?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitToBox property on a Document ContainingCollectionView: Opt; ContainingCollectionDoc: Opt; + suppressSetHeight?: boolean; thumbShown?: () => boolean; isHovering?: () => boolean; setContentView?: (view: DocComponentView) => any; @@ -842,11 +843,7 @@ export class DocumentViewInternal extends DocComponent this.props.ScreenToLocalTransform().translate(0, -this.headerMargin); contentScaling = () => this.ContentScale; onClickFunc = () => this.onClickHandler; - setHeight = (height: number) => { - if (this.props.renderDepth !== -1) { - this.layoutDoc._height = height; - } - } + setHeight = (height: number) => this.layoutDoc._height = height; setContentView = action((view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view); isContentActive = (outsideReaction?: boolean) => { return this.props.isContentActive() === false ? false : ( @@ -890,7 +887,7 @@ export class DocumentViewInternal extends DocComponent { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); } - @computed get shouldNotScale() { return (this.fitWidth && !this.nativeWidth) || this.props.treeViewDoc || [CollectionViewType.Docking].includes(this.Document._viewType as any); } + @computed get shouldNotScale() { + return (this.fitWidth && !this.nativeWidth) || + this.props.ContainingCollectionView?.collectionViewType === CollectionViewType.Time || + this.props.treeViewDoc || [CollectionViewType.Docking].includes(this.Document._viewType as any); + } @computed get effectiveNativeWidth() { return this.shouldNotScale ? 0 : (this.nativeWidth || NumCast(this.layoutDoc.width)); } @computed get effectiveNativeHeight() { return this.shouldNotScale ? 0 : (this.nativeHeight || NumCast(this.layoutDoc.height)); } @computed get nativeScaling() { @@ -1324,7 +1325,7 @@ export class DocumentView extends React.Component { position: this.props.Document.isInkMask ? "absolute" : undefined, 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()}%`, - height: (!this.props.ignoreAutoHeight && this.layoutDoc.autoHeight && this.layoutDoc.type === DocumentType.RTF) || isButton || this.props.forceAutoHeight ? undefined : yshift() ?? (this.fitWidth ? `${this.panelHeight}px` : + height: isButton || this.props.forceAutoHeight ? undefined : yshift() ?? (this.fitWidth ? `${this.panelHeight}px` : `${100 * this.effectiveNativeHeight / this.effectiveNativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%`), }}> boolean; isSelected: (outsideReaction?: boolean) => boolean; scaling?: () => number; - setHeight: (height: number) => void; + setHeight?: (height: number) => void; // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) pointerEvents?: string; diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index eca2e3cfd..55f6d6059 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -195,6 +195,7 @@ export class LinkDocPreview extends React.Component { ContainingCollectionDoc={undefined} ContainingCollectionView={undefined} renderDepth={-1} + suppressSetHeight={true} PanelWidth={this.width} PanelHeight={this.height} focus={DocUtils.DefaultFocus} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 0fd193977..eeb7b925b 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -164,7 +164,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { if (autoHeight) { this.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]); - this.props.setHeight(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1)); + this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1)); } }); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index dc1c67bea..710270be4 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1524,7 +1524,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (children) { const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins); const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight); - if (scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation + if (this.props.setHeight && scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight; if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) { setScrollHeight(); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 9aaa6e90f..92a69c02b 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -123,7 +123,7 @@ export class PDFViewer extends React.Component { autoHeight => { if (autoHeight) { this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]); - this.props.setHeight(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1)); + this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1)); } }); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 15df673f3..63af8401c 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1108,7 +1108,7 @@ export namespace Doc { if (typeof value === "string") { value = value.replace(`,${Utils.noRecursionHack}`, ""); } - const fieldVal = doc[key]; + const fieldVal = key === "#" ? (StrCast(doc.tags).includes(":#" + value + ":") ? StrCast(doc.tags) : undefined) : doc[key]; if (Cast(fieldVal, listSpec("string"), []).length) { const vals = Cast(fieldVal, listSpec("string"), []); const docs = vals.some(v => (v as any) instanceof Doc); -- cgit v1.2.3-70-g09d2 From f4b6942fc1cad1f7e7ec7552e22f6c56bc158a77 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 26 Apr 2022 14:35:49 -0400 Subject: made creating a new thumbnail icon delete previous ones. fixed bug where documents would re-render if an earlier docuent in the collection list was added/removed. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 7 +++---- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 3 +-- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 5 +++-- src/client/views/nodes/WebBox.tsx | 2 +- src/server/ApiManagers/UploadManager.ts | 12 ++++++++---- 6 files changed, 17 insertions(+), 14 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a14405a0b..bdae5a4f8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1147,7 +1147,7 @@ export class CollectionFreeFormView extends CollectionSubView this.props.isSelected() || this.props.isContentActive(); - getChildDocView(entry: PoolData, renderIndex: number) { + getChildDocView(entry: PoolData) { const childLayout = entry.pair.layout; const childData = entry.pair.data; const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); @@ -1156,7 +1156,6 @@ export class CollectionFreeFormView extends CollectionSubView this.isCurrent(entry[1].pair.layout)).forEach((entry, i) => elements.push({ - ele: this.getChildDocView(entry[1], i), + ele: this.getChildDocView(entry[1]), bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica) })); @@ -1436,7 +1435,7 @@ export class CollectionFreeFormView extends CollectionSubView { - VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true).then( + VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true, this.layoutDoc[Id] + "-icon").then( returnedfilename => setTimeout(action(() => { this.dataDoc.icon = new ImageField(returnedfilename); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 6097425e1..3f16d3c49 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable } from "mobx"; +import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { Doc, Opt } from "../../../fields/Doc"; import { List } from "../../../fields/List"; @@ -28,7 +28,6 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { jitterRotation: number; dataTransition?: string; replica: string; - renderIndex: number; CollectionFreeFormView: CollectionFreeFormView; } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 54c4be24d..23749d479 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -93,7 +93,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { - VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true).then( + VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true, this.layoutDoc[Id] + "-icon").then( returnedfilename => setTimeout(action(() => { this.dataDoc.icon = new ImageField(returnedfilename); this.dataDoc["icon-nativeWidth"] = nativeWidth; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index c31d38b0d..e57cb1abe 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -53,14 +53,15 @@ export class VideoBox extends ViewBoxAnnotatableComponent { - VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-thumb" + (new Date()).getTime(), true).then( + VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true, this.layoutDoc[Id] + "-icon").then( returnedfilename => setTimeout(action(() => this.layoutDoc.thumb = new ImageField(returnedfilename)), 500)); }) .catch(function (error: any) { diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index bfa07d47a..5e0cd67cc 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -3,7 +3,7 @@ import { Method, _success } from "../RouteManager"; import * as formidable from 'formidable'; import v4 = require('uuid/v4'); const AdmZip = require('adm-zip'); -import { extname, basename, dirname } from 'path'; +import { extname, basename, dirname, } from 'path'; import { createReadStream, createWriteStream, unlink, writeFile } from "fs"; import { publicDirectory, filesDirectory } from ".."; import { Database } from "../database"; @@ -13,10 +13,8 @@ import { AcceptableMedia, Upload } from "../SharedMediaTypes"; import { normalize } from "path"; import RouteSubscriber from "../RouteSubscriber"; const imageDataUri = require('image-data-uri'); -import { isWebUri } from "valid-url"; -import { Opt } from "../../fields/Doc"; import { SolrManager } from "./SearchManager"; -import { StringDecoder } from "string_decoder"; +let fs = require('fs'); export enum Directory { parsed_files = "parsed_files", @@ -260,10 +258,16 @@ export default class UploadManager extends ApiManager { const uri = req.body.uri; const filename = req.body.name; const origSuffix = req.body.nosuffix ? SizeSuffix.None : SizeSuffix.Original; + const deleteFiles = req.body.replaceRootFilename; if (!uri || !filename) { res.status(401).send("incorrect parameters specified"); return; } + if (deleteFiles) { + const path = serverPathToFile(Directory.images, ""); + let regex = new RegExp(`${deleteFiles}.*`); + fs.readdirSync(path).filter((f: any) => regex.test(f)).map((f: any) => fs.unlinkSync(path + f)); + } return imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => { const ext = extname(savedName).toLowerCase(); const { pngs, jpgs } = AcceptableMedia; -- cgit v1.2.3-70-g09d2 From d3eac62cbc55f186d9e2d3cc47407087fdc03ec7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 28 Apr 2022 00:21:27 -0400 Subject: fixed pushpin behavior when target is near top or bottom of scrollable document. --- src/Utils.ts | 6 +++--- src/client/views/nodes/WebBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 38eb51529..205f9379e 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -204,11 +204,11 @@ export namespace Utils { return { h: h, s: s, l: l }; } - export function scrollIntoView(targetY: number, targetHgt: number, scrollTop: number, contextHgt: number, minSpacing: number) { - if (scrollTop + contextHgt < targetY + minSpacing + targetHgt) { + export function scrollIntoView(targetY: number, targetHgt: number, scrollTop: number, contextHgt: number, minSpacing: number, scrollHeight: number) { + if (scrollTop + contextHgt < Math.min(scrollHeight, targetY + minSpacing + targetHgt)) { return Math.ceil(targetY + minSpacing + targetHgt - contextHgt); } - if (scrollTop > targetY - minSpacing - targetHgt) { + if (scrollTop > Math.max(0, targetY - minSpacing - targetHgt)) { return Math.max(0, Math.floor(targetY - minSpacing - targetHgt)); } } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 6a3c6336d..5a39123b9 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -243,7 +243,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { let focusSpeed: Opt; if (doc !== this.props.rootDoc && mainCont) { const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1); - const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, .1 * windowHeight); + const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, .1 * windowHeight, NumCast(this.props.Document.scrollHeight)); if (scrollTo !== undefined) { focusSpeed = 500; -- cgit v1.2.3-70-g09d2 From 55a5322fffc09bde04ef8b466e19b701bad2762b Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 29 Apr 2022 17:38:06 -0400 Subject: added 'enter' to toggle iconify. fixed webBox deiconify to render webpage. updated colors in minimap to match icon colors. --- src/client/views/DocumentDecorations.tsx | 11 ++++++----- src/client/views/GlobalKeyHandler.ts | 4 ++++ src/client/views/collections/TabDocView.tsx | 17 ++++++++++++++--- src/client/views/nodes/WebBox.tsx | 8 ++++---- 4 files changed, 28 insertions(+), 12 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 1feb643df..fb8cfbc15 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -146,14 +146,15 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P _deleteAfterIconify = false; _iconifyBatch: UndoManager.Batch | undefined; - onCloseClick = (force = false) => { + onCloseClick = (forceDeleteOrIconify: boolean | undefined) => { if (this.canDelete) { const views = SelectionManager.Views().slice().filter(v => v); - this._deleteAfterIconify = force || this._iconifyBatch ? true : false; + if (forceDeleteOrIconify === false && this._iconifyBatch) return; + this._deleteAfterIconify = forceDeleteOrIconify || this._iconifyBatch ? true : false; if (!this._iconifyBatch) { this._iconifyBatch = UndoManager.StartBatch("iconifying"); } else { - force = false; // can't force immediate close in the middle of iconifying -- have to wait until iconifying completes + forceDeleteOrIconify = false; // can't force immediate close in the middle of iconifying -- have to wait until iconifying completes } var iconifyingCount = views.length; const finished = action((force?: boolean) => { @@ -166,7 +167,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P this._iconifyBatch = undefined; } }); - if (force) finished(force); + if (forceDeleteOrIconify) finished(forceDeleteOrIconify); else if (!this._deleteAfterIconify) views.forEach(dv => dv.iconify(finished)); } } @@ -531,7 +532,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P left: bounds.x - this._resizeBorderWidth / 2, top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight, }}> - {!canDelete ?
: topBtn("close", this.hasIcons ? "times" : "window-maximize", undefined, e => this.onCloseClick(this.hasIcons), "Close")} + {!canDelete ?
: topBtn("close", this.hasIcons ? "times" : "window-maximize", undefined, e => this.onCloseClick(this.hasIcons ? true : undefined), "Close")} {titleArea} {!canOpen ? (null) : topBtn("open", "external-link-alt", this.onMaximizeDown, undefined, "Open in Tab (ctrl: as alias, shift: in new collection)")} {hideResizers ? (null) : diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 6120c4c9e..914802041 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -139,6 +139,10 @@ export class KeyManager { window.getSelection()?.empty(); document.body.focus(); break; + case "enter": { + DocumentDecorations.Instance.onCloseClick(false); + break; + } case "delete": case "backspace": if (document.activeElement?.tagName !== "INPUT" && document.activeElement?.tagName !== "TEXTAREA") { diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 8e45ec3b3..78b125e07 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -443,9 +443,20 @@ export class TabMinimapView extends React.Component { default: return DefaultStyleProvider(doc, props, property); case StyleProp.PointerEvents: return "none"; case StyleProp.DocContents: - const background = doc.type === DocumentType.PDF ? "red" : doc.type === DocumentType.IMG ? "blue" : doc.type === DocumentType.RTF ? "orange" : - doc.type === DocumentType.VID ? "purple" : doc.type === DocumentType.WEB ? "yellow" : doc.type === DocumentType.MAP ? "blue" : "gray"; - return doc.type === DocumentType.COL ? + const background = ((type: DocumentType) => { + switch (type) { + case DocumentType.PDF: return "pink"; + case DocumentType.AUDIO: return "lightgreen"; + case DocumentType.WEB: return "brown"; + case DocumentType.IMG: return "blue"; + case DocumentType.MAP: return "orange"; + case DocumentType.VID: return "purple"; + case DocumentType.RTF: return "yellow"; + case DocumentType.COL: return undefined; + default: return "gray"; + } + })(doc.type as DocumentType); + return !background ? undefined :
; } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 5a39123b9..5c72417cc 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -158,7 +158,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.layoutDoc._autoHeight, autoHeight => { @@ -202,10 +202,10 @@ export class WebBox extends ViewBoxAnnotatableComponent disposer?.()); - this._iframe?.removeEventListener('wheel', this.iframeWheel, true); - this._iframe?.contentDocument?.removeEventListener("pointerup", this.iframeUp); + // this._iframe?.removeEventListener('wheel', this.iframeWheel, true); + // this._iframe?.contentDocument?.removeEventListener("pointerup", this.iframeUp); } @action -- cgit v1.2.3-70-g09d2 From 6d2d18385e09da7645ff9c077240820f2d2043c9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 2 May 2022 11:04:45 -0400 Subject: fixed up html clippings to have a better background color heuristic and to allow dragging clippings from webBox's. --- src/client/views/MarqueeAnnotator.tsx | 6 ++-- src/client/views/collections/CollectionSubView.tsx | 5 ++-- src/client/views/nodes/WebBox.scss | 11 ++++--- src/client/views/nodes/WebBox.tsx | 35 +++++++++++++++++----- 4 files changed, 40 insertions(+), 17 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index a6b012bd6..2c7b04495 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -27,7 +27,7 @@ export interface MarqueeAnnotatorProps { containerOffset?: () => number[]; mainCont: HTMLDivElement; docView: DocumentView; - savedAnnotations: ObservableMap; + savedAnnotations: () => ObservableMap; annotationLayer: HTMLDivElement; addDocument: (doc: Doc) => boolean; getPageFromScroll?: (top: number) => number; @@ -128,7 +128,7 @@ export class MarqueeAnnotator extends React.Component { @undoBatch @action makeAnnotationDocument = (color: string, isLinkButton?: boolean, savedAnnotations?: ObservableMap): Opt => { - const savedAnnoMap = savedAnnotations ?? this.props.savedAnnotations; + const savedAnnoMap = savedAnnotations ?? this.props.savedAnnotations(); if (savedAnnoMap.size === 0) return undefined; const savedAnnos = Array.from(savedAnnoMap.values())[0]; if (savedAnnos.length && (savedAnnos[0] as any).marqueeing) { @@ -239,7 +239,7 @@ export class MarqueeAnnotator extends React.Component { copy.style.height = fbounds.height.toString() + "px"; copy.className = "marqueeAnnotator-annotationBox"; (copy as any).marqueeing = true; - MarqueeAnnotator.previewNewAnnotation(this.props.savedAnnotations, this.props.annotationLayer, copy, this.props.getPageFromScroll?.(this._top) || 0); + MarqueeAnnotator.previewNewAnnotation(this.props.savedAnnotations(), this.props.annotationLayer, copy, this.props.getPageFromScroll?.(this._top) || 0); } AnchorMenu.Instance.jumpTo(cliX, cliY); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 30e0adf24..247d0563a 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -317,10 +317,11 @@ export function CollectionSubView(moreProps?: X) { }); } else { const srcWeb = SelectionManager.Docs().lastElement(); - const srcUrl = (srcWeb?.data as WebField).url?.href?.match(/http[s]?:\/\/[^/]*/)?.[0]; + const srcUrl = (srcWeb?.data as WebField)?.url?.href?.match(/https?:\/\/[^/]*/)?.[0]; const reg = new RegExp(Utils.prepend(""), "g"); const modHtml = srcUrl ? html.replace(reg, srcUrl) : html; - const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: "-web page-", _width: 300, _height: 300 }); + const backgroundColor = tags.map(tag => tag.match(/.*(background-color: ?[^;]*)/)?.[1]?.replace(/background-color: ?(.*)/, "$1")).filter(t => t)?.[0]; + const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: srcUrl ? "from:" + srcUrl : "-web clip-", _width: 300, _height: 300, backgroundColor }); Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc).text = text; addDocument(htmlDoc); if (srcWeb) { diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index ff38e37dd..b037e7220 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -5,17 +5,18 @@ height: 100%; position: relative; display: flex; - .webBox-sideResizer { + + .webBox-sideResizer { position: absolute; width: 100%; height: 100%; cursor: ew-resize; background: darkgray; } - .webBox-background { + + .webBox-background { width: 100%; height: 100%; - background: lightGray; } .webBox-ui { @@ -120,7 +121,7 @@ box-shadow: $standard-box-shadow; transition: 0.2s; - &:hover{ + &:hover { filter: brightness(0.85); } } @@ -160,6 +161,7 @@ .webBox-cont { pointer-events: none; } + .webBox-cont, .webBox-cont-interactive { padding: 0vw; @@ -193,6 +195,7 @@ top: 0; left: 0; overflow: auto; + .webBox-innerContent { position: relative; } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 5c72417cc..4d4ed6c67 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -80,8 +80,6 @@ export class WebBox extends ViewBoxAnnotatableComponent this._webUrl = this._url); // setting the weburl will change the src parameter of the embedded iframe and force a navigation to it. } @@ -231,6 +229,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.urlEditor; // controls to be added to the top bar when a document of this type is selected @@ -256,6 +255,8 @@ export class WebBox extends ViewBoxAnnotatableComponent { + + // this.createTextAnnotation(sel, sel.getRangeAt(0)); const anchor = AnchorMenu.Instance?.GetAnchor(this._savedAnnotations) ?? Docs.Create.WebanchorDocument(this._url, { @@ -267,6 +268,9 @@ export class WebBox extends ViewBoxAnnotatableComponent ObservableMap) | undefined; + savedAnnotationsCreator: (() => ObservableMap) = () => this._textAnnotationCreator?.() || this._savedAnnotations; + @action iframeUp = (e: PointerEvent) => { this.props.docViewPath().lastElement()?.docView?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here. @@ -275,7 +279,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.createTextAnnotation(sel, sel.getRangeAt(0)); AnchorMenu.Instance.jumpTo(e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._scrollTop) * scale); } @@ -283,6 +287,8 @@ export class WebBox extends ViewBoxAnnotatableComponent { + this._textAnnotationCreator = undefined; + const sel = this._iframe?.contentWindow?.getSelection?.(); const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); const scale = (this.props.scaling?.() || 1) * mainContBounds.scale; const word = getWordAtPoint(e.target, e.clientX, e.clientY); @@ -546,6 +552,9 @@ export class WebBox extends ViewBoxAnnotatableComponent = undefined; @observable _previewWidth: Opt = undefined; toggleSidebar = action((preview: boolean = false) => { - const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); + var nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); + if (!nativeWidth) { + const defaultNativeWidth = this.dataDoc[this.fieldKey] instanceof WebField ? 850 : this.Document[WidthSym](); + Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || defaultNativeWidth); + Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || this.Document[HeightSym]() / this.Document[WidthSym]() * defaultNativeWidth); + nativeWidth = NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]); + } const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth + WebBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth; const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); @@ -620,9 +635,13 @@ export class WebBox extends ViewBoxAnnotatableComponent !this.SidebarShown ? 0 : @@ -716,7 +735,7 @@ export class WebBox extends ViewBoxAnnotatableComponent -
+
}
-- cgit v1.2.3-70-g09d2 From 53977c52c65e7b0856e08386435375d210f5f7b7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 2 May 2022 12:15:21 -0400 Subject: fixed auto link anchor when dragging html region off of webBox. fixed Enter for earch in webBox. --- src/client/views/MarqueeAnnotator.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 17 ++++------------- src/client/views/nodes/WebBox.tsx | 11 +++++------ 3 files changed, 10 insertions(+), 20 deletions(-) (limited to 'src/client/views/nodes/WebBox.tsx') diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 2c7b04495..e15624e23 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -128,7 +128,7 @@ export class MarqueeAnnotator extends React.Component { @undoBatch @action makeAnnotationDocument = (color: string, isLinkButton?: boolean, savedAnnotations?: ObservableMap): Opt => { - const savedAnnoMap = savedAnnotations ?? this.props.savedAnnotations(); + const savedAnnoMap = savedAnnotations?.values() && Array.from(savedAnnotations?.values()).length ? savedAnnotations : this.props.savedAnnotations(); if (savedAnnoMap.size === 0) return undefined; const savedAnnos = Array.from(savedAnnoMap.values())[0]; if (savedAnnos.length && (savedAnnos[0] as any).marqueeing) { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 247d0563a..17fdba764 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -316,8 +316,8 @@ export function CollectionSubView(moreProps?: X) { } }); } else { - const srcWeb = SelectionManager.Docs().lastElement(); - const srcUrl = (srcWeb?.data as WebField)?.url?.href?.match(/https?:\/\/[^/]*/)?.[0]; + const srcWeb = SelectionManager.Views().lastElement(); + const srcUrl = (srcWeb?.Document.data as WebField)?.url?.href?.match(/https?:\/\/[^/]*/)?.[0]; const reg = new RegExp(Utils.prepend(""), "g"); const modHtml = srcUrl ? html.replace(reg, srcUrl) : html; const backgroundColor = tags.map(tag => tag.match(/.*(background-color: ?[^;]*)/)?.[1]?.replace(/background-color: ?(.*)/, "$1")).filter(t => t)?.[0]; @@ -328,17 +328,8 @@ export function CollectionSubView(moreProps?: X) { const iframe = SelectionManager.Views()[0].ContentDiv?.getElementsByTagName("iframe")?.[0]; const focusNode = (iframe?.contentDocument?.getSelection()?.focusNode as any); if (focusNode) { - const rects = iframe?.contentWindow?.getSelection()?.getRangeAt(0).getClientRects(); - "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect(); - const x = (rects && Array.from(rects).reduce((x: any, r: DOMRect) => x === undefined || r.x < x ? r.x : x, undefined as any)) || 0; - const y = NumCast(srcWeb._scrollTop) + ((rects && Array.from(rects).reduce((y: any, r: DOMRect) => y === undefined || r.y < y ? r.y : y, undefined as any)) || 0); - const r = (rects && Array.from(rects).reduce((x: any, r: DOMRect) => x === undefined || r.x + r.width > x ? r.x + r.width : x, undefined as any)) || 0; - const b = NumCast(srcWeb._scrollTop) + ((rects && Array.from(rects).reduce((y: any, r: DOMRect) => y === undefined || r.y + r.height > y ? r.y + r.height : y, undefined as any)) || 0); - const anchor = Docs.Create.FreeformDocument([], { backgroundColor: "transparent", _width: r - x, _height: b - y, x, y, annotationOn: srcWeb }); - anchor.context = srcWeb; - const key = Doc.LayoutFieldKey(srcWeb); - Doc.AddDocToList(srcWeb, key + "-annotations", anchor); - DocUtils.MakeLink({ doc: htmlDoc }, { doc: anchor }); + const anchor = srcWeb?.ComponentView?.getAnchor?.(); + anchor && DocUtils.MakeLink({ doc: htmlDoc }, { doc: anchor }); } } } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 4d4ed6c67..80961c92f 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -12,7 +12,7 @@ import { ComputedField } from "../../../fields/ScriptField"; 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, Utils } from "../../../Utils"; +import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, StopEvent, Utils } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { KeyCodes } from "../../util/KeyCodes"; @@ -235,6 +235,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.urlEditor; // controls to be added to the top bar when a document of this type is selected scrollFocus = (doc: Doc, smooth: boolean) => { + this.props.select(true); if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), !smooth); if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) { this.toggleSidebar(!smooth); @@ -255,8 +256,6 @@ export class WebBox extends ViewBoxAnnotatableComponent { - - // this.createTextAnnotation(sel, sel.getRangeAt(0)); const anchor = AnchorMenu.Instance?.GetAnchor(this._savedAnnotations) ?? Docs.Create.WebanchorDocument(this._url, { @@ -273,6 +272,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { + this._textAnnotationCreator = undefined; this.props.docViewPath().lastElement()?.docView?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here. if (this._iframe?.contentWindow && this._iframe.contentDocument && !this._iframe.contentWindow.getSelection()?.isCollapsed) { const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); @@ -287,7 +287,6 @@ export class WebBox extends ViewBoxAnnotatableComponent { - this._textAnnotationCreator = undefined; const sel = this._iframe?.contentWindow?.getSelection?.(); const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); const scale = (this.props.scaling?.() || 1) * mainContBounds.scale; @@ -571,7 +570,7 @@ export class WebBox extends ViewBoxAnnotatableComponent; + view = e.stopPropagation()} dangerouslySetInnerHTML={{ __html: field.html }} />; } else if (field instanceof WebField) { const url = this.layoutDoc.useCors ? Utils.CorsProxy(this._webUrl) : this._webUrl; view =