From 7e439440a1d7fc3e3b29333b0502d6ed4d178309 Mon Sep 17 00:00:00 2001 From: vkalev Date: Wed, 18 Aug 2021 12:12:23 -0400 Subject: highlighter tool added & working --- src/client/util/InteractionUtils.tsx | 6 ++++-- src/client/views/GestureOverlay.tsx | 6 ++++-- src/client/views/InkHandles.tsx | 2 -- src/client/views/InkingStroke.tsx | 23 +++++++++++++++++------ src/client/views/collections/CollectionMenu.tsx | 21 ++++++++++++++------- 5 files changed, 39 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index e009fb3a9..15a6709a2 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -3,6 +3,8 @@ import * as beziercurve from 'bezier-curve'; import * as fitCurve from 'fit-curve'; import "./InteractionUtils.scss"; import { Utils } from "../../Utils"; +import { CurrentUserUtils } from "./CurrentUserUtils"; +import { InkTool } from "../../fields/InkField"; export namespace InteractionUtils { export const MOUSETYPE = "mouse"; @@ -139,7 +141,7 @@ export namespace InteractionUtils { export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color: string, width: number, strokeWidth: number, bezier: string, fill: string, arrowStart: string, arrowEnd: string, - dash: string | undefined, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean, nodefs: boolean) { + dash: string | undefined, scalex: number, scaley: number, shape: string, pevents: string, opacity: number, nodefs: boolean) { let pts: { X: number; Y: number; }[] = []; if (shape) { //if any of the shape are true pts = makePolygon(shape, points); @@ -210,7 +212,7 @@ export namespace InteractionUtils { style={{ // filter: drawHalo ? "url(#inkSelectionHalo)" : undefined, fill: fill ? fill : "none", - opacity: 1.0, + opacity: opacity, // opacity: strokeWidth !== width ? 0.5 : undefined, pointerEvents: pevents as any, stroke: color ?? "rgb(0, 0, 0)", diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index bbf21f22c..c77521572 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -494,6 +494,7 @@ export class GestureOverlay extends Touchable { if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { 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)"); } } @@ -733,6 +734,7 @@ export class GestureOverlay extends Touchable { const centerX = (Math.max(left, right) + Math.min(left, right)) / 2; const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2; const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom)); + // Dividing the circle into four equal sections, and fitting each section to a cubic Bézier curve. this._points.push({ X: centerX - radius, Y: centerY }); this._points.push({ X: centerX - radius, Y: centerY + (c * radius) }); @@ -842,12 +844,12 @@ export class GestureOverlay extends Touchable { return {InteractionUtils.CreatePolyline(l, b.left, b.top, ActiveInkColor(), width, width, ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), - ActiveDash(), 1, 1, this.InkShape, "none", false, false)} + ActiveDash(), 1, 1, this.InkShape, "none", 1.0, false)} ; }), this._points.length <= 1 ? (null) : - {InteractionUtils.CreatePolyline(this._points.map(p => ({ X: p.X, Y: p.Y - (rect?.y || 0) })), B.left, B.top, ActiveInkColor(), width, width, ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), 1, 1, this.InkShape, "none", false, false)} + {InteractionUtils.CreatePolyline(this._points.map(p => ({ X: p.X, Y: p.Y - (rect?.y || 0) })), B.left, B.top, ActiveInkColor(), width, width, ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), 1, 1, this.InkShape, "none", 1.0, false)} ] ]; } diff --git a/src/client/views/InkHandles.tsx b/src/client/views/InkHandles.tsx index 0b24c3c32..b9f75f8d7 100644 --- a/src/client/views/InkHandles.tsx +++ b/src/client/views/InkHandles.tsx @@ -16,7 +16,6 @@ import { GestureOverlay } from "./GestureOverlay"; export interface InkHandlesProps { inkDoc: Doc; data: InkData; - shape?: string; format: number[]; ScreenToLocalTransform: () => Transform; } @@ -70,7 +69,6 @@ export class InkHandles extends React.Component { // Accessing the current ink's data and extracting all handle points and handle lines. const data = this.props.data; - const shape = this.props.shape; const handlePoints: HandlePoint[] = []; const handleLines: HandleLine[] = []; if (data.length >= 4) { diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 5fc159f14..7200d6da1 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -29,11 +29,13 @@ const InkDocument = makeInterface(documentSchema); export class InkingStroke extends ViewBoxBaseComponent(InkDocument) { static readonly MaskDim = 50000; @observable private _properties?: InkStrokeProperties; + // @observable private _previousColor: string; constructor(props: FieldViewProps & InkDocument) { super(props); this._properties = InkStrokeProperties.Instance; + // this._previousColor = ActiveInkColor(); } public static LayoutString(fieldStr: string) { @@ -75,12 +77,22 @@ export class InkingStroke extends ViewBoxBaseComponent { + if (CurrentUserUtils.SelectedTool === InkTool.Highlighter) { + // this._previousColor = ActiveInkColor(); + SetActiveInkColor("rgba(245, 230, 95, 0.75)"); + } + // } else { + // SetActiveInkColor(this._previousColor); + // } + } + render() { TraceMobx(); this.toggleControlButton(); + // this.checkHighlighter(); // Extracting the ink data and formatting information of the current ink stroke. - // console.log(InkingStroke.InkShape); - const InkShape = GestureOverlay.Instance.InkShape; const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? []; const inkDoc: Doc = this.layoutDoc; const strokeWidth = Number(this.layoutDoc.strokeWidth); @@ -101,13 +113,13 @@ export class InkingStroke extends ViewBoxBaseComponent 1 && lineRight - lineLeft > 1, false); + StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false); // Thin blue line indicating that the current ink stroke is selected. const selectedLine = InteractionUtils.CreatePolyline(data, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), - StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5 && lineBottom - lineTop > 1 && lineRight - lineLeft > 1, false); + StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false); // Invisible polygonal line that enables the ink to be selected by the user. const clickableLine = InteractionUtils.CreatePolyline(data, left, top, "transparent", strokeWidth, strokeWidth + 15, StrCast(this.layoutDoc.strokeBezier), - StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, scaleX, scaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", false, true); + StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, scaleX, scaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", 0.0, true); // Set of points rendered upon the ink that can be added if a user clicks on one. const addedPoints = InteractionUtils.CreatePoints(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5, false); @@ -145,7 +157,6 @@ export class InkingStroke extends ViewBoxBaseComponent : ""} diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 8f4df4a92..835b3e575 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -614,12 +614,12 @@ export class CollectionFreeFormViewChrome extends React.Component Date: Sat, 21 Aug 2021 16:55:55 -0400 Subject: added unrounded endpoints for highlight ink strokes --- src/client/util/InteractionUtils.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 15a6709a2..a11c090a7 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -217,8 +217,8 @@ export namespace InteractionUtils { pointerEvents: pevents as any, stroke: color ?? "rgb(0, 0, 0)", strokeWidth: strokeWidth, - strokeLinejoin: "round", - strokeLinecap: "round", + strokeLinejoin: color === "rgba(245, 230, 95, 0.75)" ? "miter" : "round", + strokeLinecap: color === "rgba(245, 230, 95, 0.75)" ? "square" : "round", strokeDasharray: dashArray }} markerStart={`url(#${arrowStart + "Start" + defGuid})`} -- cgit v1.2.3-70-g09d2 From 8cb650d9fb542465525c198c1f93f6aba7256e0b Mon Sep 17 00:00:00 2001 From: vkalev Date: Thu, 2 Sep 2021 12:04:02 -0400 Subject: working on moving ink UI to DocumentDecorations --- src/client/views/DocumentDecorations.tsx | 40 ++++++++++++++++++++++++++++---- src/client/views/GestureOverlay.tsx | 19 ++++++++------- src/client/views/InkingStroke.tsx | 6 ++--- src/client/views/MainView.tsx | 3 ++- 4 files changed, 50 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 118d2e7c7..244d14f3a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -28,9 +28,11 @@ import { DocumentView } from "./nodes/DocumentView"; import React = require("react"); import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { DateField } from '../../fields/DateField'; +import { InteractionUtils } from '../util/InteractionUtils'; +import { Colors } from './global/globalEnums'; @observer -export class DocumentDecorations extends React.Component<{ boundsLeft: number, boundsTop: number }, { value: string }> { +export class DocumentDecorations extends React.Component<{ PanelWidth: number, PanelHeight: number, boundsLeft: number, boundsTop: number }, { value: string }> { static Instance: DocumentDecorations; private _resizeHdlId = ""; private _keyinput = React.createRef(); @@ -391,10 +393,10 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => { Doc.GetProto(doc).data = new InkField(inkPts.map(ipt => // (new x — oldx) + newWidth * (oldxpoint /oldWidth) - ({ - X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width, - Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height - }))); + ({ + X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width, + Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height + }))); Doc.SetNativeWidth(doc, undefined); Doc.SetNativeHeight(doc, undefined); }); @@ -453,7 +455,34 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b const borderRadiusDraggerWidth = 15; bounds.r = Math.max(bounds.x, Math.max(leftBounds, Math.min(window.innerWidth, bounds.r + borderRadiusDraggerWidth + this._resizeBorderWidth / 2) - this._resizeBorderWidth / 2 - borderRadiusDraggerWidth)); bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight)); + const useRotation = seldoc.rootDoc.type === DocumentType.INK; + const docView = SelectionManager.Views().lastElement().docView; + let selectedLine = null; + + if (useRotation && docView) { + const inkData = Cast(SelectionManager.Views().lastElement().rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }]; + const inkDoc = SelectionManager.Views().lastElement().layoutDoc; + + inkData.map((point) => { docView.screenToLocal().inverse().transformPoint(point.X, point.Y); }); + + const strokeWidth = 4; + const lineTop = Math.min(...inkData.map(p => p.Y)); + const lineBottom = Math.max(...inkData.map(p => p.Y)); + const lineLeft = Math.min(...inkData.map(p => p.X)); + const lineRight = Math.max(...inkData.map(p => p.X)); + const left = lineLeft - strokeWidth / 2; + const top = lineTop - strokeWidth / 2; + const right = lineRight + strokeWidth / 2; + const bottom = lineBottom + strokeWidth / 2; + const width = Math.max(1, right - left); + const height = Math.max(1, bottom - top); + const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth - strokeWidth) / (width - strokeWidth); + const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight - strokeWidth) / (height - strokeWidth); + + selectedLine = InteractionUtils.CreatePolyline(inkData, left, top, Colors.MEDIUM_BLUE, 4, 4, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), + StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false); + } return (
{!canDelete ?
: topBtn("close", "times", undefined, this.onCloseClick, "Close")} {seldoc.props.hideDecorationTitle || seldoc.props.Document.type === DocumentType.EQUATION ? (null) : titleArea} + {selectedLine} {seldoc.props.hideResizeHandles || seldoc.props.Document.type === DocumentType.EQUATION ? (null) : <> {SelectionManager.Views().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) : diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index c77521572..d0059dacc 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -688,25 +688,26 @@ export class GestureOverlay extends Touchable { case "rectangle": this._points.push({ X: left, Y: top }); this._points.push({ X: left, Y: top }); - this._points.push({ X: right, Y: top }); this._points.push({ X: right, Y: top }); + this._points.push({ X: right, Y: top }); this._points.push({ X: right, Y: top }); - this._points.push({ X: right, Y: bottom }); this._points.push({ X: right, Y: bottom }); + this._points.push({ X: right, Y: bottom }); this._points.push({ X: right, Y: bottom }); - this._points.push({ X: left, Y: bottom }); this._points.push({ X: left, Y: bottom }); + this._points.push({ X: left, Y: bottom }); this._points.push({ X: left, Y: bottom }); - this._points.push({ X: left, Y: top }); this._points.push({ X: left, Y: top }); + break; + case "triangle": this._points.push({ X: left, Y: bottom }); this._points.push({ X: left, Y: bottom }); @@ -736,11 +737,6 @@ export class GestureOverlay extends Touchable { const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom)); // Dividing the circle into four equal sections, and fitting each section to a cubic Bézier curve. - this._points.push({ X: centerX - radius, Y: centerY }); - this._points.push({ X: centerX - radius, Y: centerY + (c * radius) }); - this._points.push({ X: centerX - (c * radius), Y: centerY + radius }); - this._points.push({ X: centerX, Y: centerY + radius }); - this._points.push({ X: centerX, Y: centerY + radius }); this._points.push({ X: centerX + (c * radius), Y: centerY + radius }); this._points.push({ X: centerX + radius, Y: centerY + (c * radius) }); @@ -756,6 +752,11 @@ export class GestureOverlay extends Touchable { this._points.push({ X: centerX - radius, Y: centerY - (c * radius) }); this._points.push({ X: centerX - radius, Y: centerY }); + this._points.push({ X: centerX - radius, Y: centerY }); + this._points.push({ X: centerX - radius, Y: centerY + (c * radius) }); + this._points.push({ X: centerX - (c * radius), Y: centerY + radius }); + this._points.push({ X: centerX, Y: centerY + radius }); + break; case "line": diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 7200d6da1..b619f858e 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -115,8 +115,8 @@ export class InkingStroke extends ViewBoxBaseComponent - + {this.search} {LinkDescriptionPopup.descriptionPopup ? : null} {DocumentLinksButton.LinkEditorDocView ? : (null)} -- cgit v1.2.3-70-g09d2 From 04920f5deac0449524693a738cea45394be3d0fa Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 2 Sep 2021 12:41:27 -0400 Subject: fixes for making overlay ink stroke in doc decorations align with selected stroke. --- src/client/views/DocumentDecorations.scss | 5 +++++ src/client/views/DocumentDecorations.tsx | 22 ++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 316f63240..9479fd365 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -6,7 +6,12 @@ $linkGap : 3px; position: absolute; z-index: 2000; } +.documentDecorations-inkstroke { + svg:not(:root) { + overflow: visible !important; + } +} .documentDecorations-container { z-index: $docDecorations-zindex; position: absolute; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 244d14f3a..db3ec79a1 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -393,10 +393,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => { Doc.GetProto(doc).data = new InkField(inkPts.map(ipt => // (new x — oldx) + newWidth * (oldxpoint /oldWidth) - ({ - X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width, - Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height - }))); + ({ + X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width, + Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height + }))); Doc.SetNativeWidth(doc, undefined); Doc.SetNativeHeight(doc, undefined); }); @@ -480,7 +480,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth - strokeWidth) / (width - strokeWidth); const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight - strokeWidth) / (height - strokeWidth); - selectedLine = InteractionUtils.CreatePolyline(inkData, left, top, Colors.MEDIUM_BLUE, 4, 4, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), + selectedLine = InteractionUtils.CreatePolyline(inkData, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false); } @@ -502,7 +502,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P }}> {!canDelete ?
: topBtn("close", "times", undefined, this.onCloseClick, "Close")} {seldoc.props.hideDecorationTitle || seldoc.props.Document.type === DocumentType.EQUATION ? (null) : titleArea} - {selectedLine} {seldoc.props.hideResizeHandles || seldoc.props.Document.type === DocumentType.EQUATION ? (null) : <> {SelectionManager.Views().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) : @@ -525,6 +524,17 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P }
+
+ {selectedLine} +
{seldoc?.Document.type === DocumentType.FONTICON ? (null) :
} -- cgit v1.2.3-70-g09d2 From 7840b15be359c5ef3b7efd5154177d82e919c2d5 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 2 Sep 2021 12:49:51 -0400 Subject: fix for transforming inkpoints in docdecorations. --- src/client/views/DocumentDecorations.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index db3ec79a1..be9ab7960 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -464,13 +464,13 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P const inkData = Cast(SelectionManager.Views().lastElement().rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }]; const inkDoc = SelectionManager.Views().lastElement().layoutDoc; - inkData.map((point) => { docView.screenToLocal().inverse().transformPoint(point.X, point.Y); }); + const points = inkData.map((point) => docView.screenToLocal().inverse().transformPoint(point.X, point.Y)).map(p => ({ X: p[0], Y: p[1] })); const strokeWidth = 4; - const lineTop = Math.min(...inkData.map(p => p.Y)); - const lineBottom = Math.max(...inkData.map(p => p.Y)); - const lineLeft = Math.min(...inkData.map(p => p.X)); - const lineRight = Math.max(...inkData.map(p => p.X)); + const lineTop = Math.min(...points.map(p => p.Y)); + const lineBottom = Math.max(...points.map(p => p.Y)); + const lineLeft = Math.min(...points.map(p => p.X)); + const lineRight = Math.max(...points.map(p => p.X)); const left = lineLeft - strokeWidth / 2; const top = lineTop - strokeWidth / 2; const right = lineRight + strokeWidth / 2; @@ -480,7 +480,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth - strokeWidth) / (width - strokeWidth); const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight - strokeWidth) / (height - strokeWidth); - selectedLine = InteractionUtils.CreatePolyline(inkData, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), + selectedLine = InteractionUtils.CreatePolyline(points, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false); } -- cgit v1.2.3-70-g09d2 From 57243cb00f2fd575e5d5d6a79108cb97793bc01c Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 2 Sep 2021 13:20:55 -0400 Subject: from last --- src/client/views/DocumentDecorations.tsx | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index be9ab7960..a615d8b26 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -463,25 +463,26 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P if (useRotation && docView) { const inkData = Cast(SelectionManager.Views().lastElement().rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }]; const inkDoc = SelectionManager.Views().lastElement().layoutDoc; + const swidth = docView.screenToLocal().inverse().transformDirection(NumCast(seldoc.props.Document.strokeWidth, 1), NumCast(seldoc.props.Document.strokeWidth, 1)); const points = inkData.map((point) => docView.screenToLocal().inverse().transformPoint(point.X, point.Y)).map(p => ({ X: p[0], Y: p[1] })); - const strokeWidth = 4; - const lineTop = Math.min(...points.map(p => p.Y)); - const lineBottom = Math.max(...points.map(p => p.Y)); - const lineLeft = Math.min(...points.map(p => p.X)); - const lineRight = Math.max(...points.map(p => p.X)); - const left = lineLeft - strokeWidth / 2; - const top = lineTop - strokeWidth / 2; - const right = lineRight + strokeWidth / 2; - const bottom = lineBottom + strokeWidth / 2; + const strokeWidth = 1; + const lineTop = Math.min(...points.map(p => p.Y)) - swidth[0] / 2; + const lineBottom = Math.max(...points.map(p => p.Y)) + swidth[0] / 2; + const lineLeft = Math.min(...points.map(p => p.X)) - swidth[0] / 2; + const lineRight = Math.max(...points.map(p => p.X)) + swidth[0] / 2; + const left = lineLeft; + const top = lineTop; + const right = lineRight; + const bottom = lineBottom; const width = Math.max(1, right - left); const height = Math.max(1, bottom - top); - const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth - strokeWidth) / (width - strokeWidth); - const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight - strokeWidth) / (height - strokeWidth); + const scaleX = width === strokeWidth ? 1 : (bounds.r - bounds.x) / (width - strokeWidth); + const scaleY = height === strokeWidth ? 1 : (bounds.b - bounds.y) / (height - strokeWidth); selectedLine = InteractionUtils.CreatePolyline(points, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), - StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false); + StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false); } return (
@@ -526,8 +527,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
Date: Thu, 2 Sep 2021 14:57:28 -0400 Subject: corrected fix to drawing ink stroke in doc decorations overlay. --- src/client/views/DocumentDecorations.tsx | 51 +++++++++++++----------------- src/client/views/InkingStroke.tsx | 54 ++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index a615d8b26..ce33f488a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -3,33 +3,33 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Tooltip } from '@material-ui/core'; import { action, computed, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; +import { DateField } from '../../fields/DateField'; import { AclAdmin, AclEdit, DataSym, Doc, Field, HeightSym, WidthSym } from "../../fields/Doc"; import { Document } from '../../fields/documentSchemas'; -import { HtmlField } from '../../fields/HtmlField'; import { InkField } from "../../fields/InkField"; import { ScriptField } from '../../fields/ScriptField'; import { Cast, NumCast, StrCast } from "../../fields/Types"; import { GetEffectiveAcl } from '../../fields/util'; -import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils"; -import { Docs, DocUtils } from "../documents/Documents"; +import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../Utils"; +import { Docs } from "../documents/Documents"; import { DocumentType } from '../documents/DocumentTypes'; import { CurrentUserUtils } from '../util/CurrentUserUtils'; import { DragManager } from "../util/DragManager"; +import { InteractionUtils } from '../util/InteractionUtils'; import { SelectionManager } from "../util/SelectionManager"; import { SnappingManager } from '../util/SnappingManager'; import { undoBatch, UndoManager } from "../util/UndoManager"; import { CollectionDockingView } from './collections/CollectionDockingView'; import { DocumentButtonBar } from './DocumentButtonBar'; import './DocumentDecorations.scss'; +import { Colors } from './global/globalEnums'; import { KeyManager } from './GlobalKeyHandler'; +import { InkingStroke } from './InkingStroke'; import { InkStrokeProperties } from './InkStrokeProperties'; import { LightboxView } from './LightboxView'; import { DocumentView } from "./nodes/DocumentView"; -import React = require("react"); import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; -import { DateField } from '../../fields/DateField'; -import { InteractionUtils } from '../util/InteractionUtils'; -import { Colors } from './global/globalEnums'; +import React = require("react"); @observer export class DocumentDecorations extends React.Component<{ PanelWidth: number, PanelHeight: number, boundsLeft: number, boundsTop: number }, { value: string }> { @@ -457,32 +457,23 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight)); const useRotation = seldoc.rootDoc.type === DocumentType.INK; - const docView = SelectionManager.Views().lastElement().docView; + const docView = seldoc.docView; let selectedLine = null; if (useRotation && docView) { - const inkData = Cast(SelectionManager.Views().lastElement().rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }]; - const inkDoc = SelectionManager.Views().lastElement().layoutDoc; - const swidth = docView.screenToLocal().inverse().transformDirection(NumCast(seldoc.props.Document.strokeWidth, 1), NumCast(seldoc.props.Document.strokeWidth, 1)); - - const points = inkData.map((point) => docView.screenToLocal().inverse().transformPoint(point.X, point.Y)).map(p => ({ X: p[0], Y: p[1] })); - - const strokeWidth = 1; - const lineTop = Math.min(...points.map(p => p.Y)) - swidth[0] / 2; - const lineBottom = Math.max(...points.map(p => p.Y)) + swidth[0] / 2; - const lineLeft = Math.min(...points.map(p => p.X)) - swidth[0] / 2; - const lineRight = Math.max(...points.map(p => p.X)) + swidth[0] / 2; - const left = lineLeft; - const top = lineTop; - const right = lineRight; - const bottom = lineBottom; - const width = Math.max(1, right - left); - const height = Math.max(1, bottom - top); - const scaleX = width === strokeWidth ? 1 : (bounds.r - bounds.x) / (width - strokeWidth); - const scaleY = height === strokeWidth ? 1 : (bounds.b - bounds.y) / (height - strokeWidth); - - selectedLine = InteractionUtils.CreatePolyline(points, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), - StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false); + const inkData = Cast(seldoc.rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }]; + const inkDoc = seldoc.layoutDoc; + const overlayInkWidth = 10; + + const { inkScaleX, inkScaleY, inkStrokeWidth } = InkingStroke.inkScaling(inkDoc, inkData, docView.props.PanelWidth(), docView.props.PanelHeight()); + + const screenInkWidth = docView.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); + const screenPts = inkData.map(point => docView.screenToLocal().inverse().transformPoint(point.X * inkScaleX, point.Y * inkScaleY)).map(p => ({ X: p[0], Y: p[1] })); + const screenTop = Math.min(...screenPts.map(p => p.Y)) - screenInkWidth[0] / 2; + const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2; + + selectedLine = InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, overlayInkWidth, overlayInkWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), + StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false); } return (
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index b619f858e..b8ab0c4d8 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -5,7 +5,7 @@ import { Doc } from "../../fields/Doc"; import { documentSchema } from "../../fields/documentSchemas"; import { InkData, InkField, InkTool } from "../../fields/InkField"; import { makeInterface } from "../../fields/Schema"; -import { Cast, StrCast } from "../../fields/Types"; +import { Cast, StrCast, NumCast } from "../../fields/Types"; import { TraceMobx } from "../../fields/util"; import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils"; import { CognitiveServices } from "../cognitive_services/CognitiveServices"; @@ -88,6 +88,24 @@ export class InkingStroke extends ViewBoxBaseComponent p.Y)) - inkStrokeWidth / 2; + const inkBottom = Math.max(...inkData.map(p => p.Y)) + inkStrokeWidth / 2; + const inkLeft = Math.min(...inkData.map(p => p.X)) - inkStrokeWidth / 2; + const inkRight = Math.max(...inkData.map(p => p.X)) + inkStrokeWidth / 2; + const inkWidth = Math.max(1, inkRight - inkLeft); + const inkHeight = Math.max(1, inkBottom - inkTop); + return { + inkStrokeWidth, + inkTop, + inkLeft, + inkWidth, + inkHeight, + inkScaleX: inkHeight === inkStrokeWidth ? 1 : (panelWidth - inkStrokeWidth) / (inkWidth - inkStrokeWidth), + inkScaleY: inkWidth === inkStrokeWidth ? 1 : (panelHeight - inkStrokeWidth) / (inkHeight - inkStrokeWidth) + }; + } render() { TraceMobx(); this.toggleControlButton(); @@ -95,34 +113,24 @@ export class InkingStroke extends ViewBoxBaseComponent p.Y)); - const lineBottom = Math.max(...data.map(p => p.Y)); - const lineLeft = Math.min(...data.map(p => p.X)); - const lineRight = Math.max(...data.map(p => p.X)); - const left = lineLeft - strokeWidth / 2; - const top = lineTop - strokeWidth / 2; - const right = lineRight + strokeWidth / 2; - const bottom = lineBottom + strokeWidth / 2; - const width = Math.max(1, right - left); - const height = Math.max(1, bottom - top); - const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth() - strokeWidth) / (width - strokeWidth); - const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight() - strokeWidth) / (height - strokeWidth); + + const { inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = InkingStroke.inkScaling(inkDoc, data, this.props.PanelWidth(), this.props.PanelHeight()); + const strokeColor = StrCast(this.layoutDoc.color, ""); - const dotsize = Math.max(width * scaleX, height * scaleY) / 40; + const dotsize = Math.max(inkWidth * inkScaleX, inkHeight * inkScaleY) / 40; // Visually renders the polygonal line made by the user. - const inkLine = InteractionUtils.CreatePolyline(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker), - StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false); + const inkLine = InteractionUtils.CreatePolyline(data, inkLeft, inkTop, strokeColor, inkStrokeWidth, inkStrokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker), + StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false); // Thin blue line indicating that the current ink stroke is selected. // const selectedLine = InteractionUtils.CreatePolyline(data, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), // StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false); // Invisible polygonal line that enables the ink to be selected by the user. - const clickableLine = InteractionUtils.CreatePolyline(data, left, top, "transparent", strokeWidth, strokeWidth + 15, StrCast(this.layoutDoc.strokeBezier), - StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, scaleX, scaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", 0.0, true); + const clickableLine = InteractionUtils.CreatePolyline(data, inkLeft, inkTop, "transparent", inkStrokeWidth, inkStrokeWidth + 15, StrCast(this.layoutDoc.strokeBezier), + StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, inkScaleX, inkScaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", 0.0, true); // Set of points rendered upon the ink that can be added if a user clicks on one. - const addedPoints = InteractionUtils.CreatePoints(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker), - StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5, false); + const addedPoints = InteractionUtils.CreatePoints(data, inkLeft, inkTop, strokeColor, inkStrokeWidth, inkStrokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker), + StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", this.props.isSelected() && inkStrokeWidth <= 5, false); return ( : ""} -- cgit v1.2.3-70-g09d2 From 610147f7d48ae5a8191fff45cb6d0a5e71bf94a5 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 2 Sep 2021 15:25:53 -0400 Subject: cleaned up overlay ink stroke in document decorations --- src/client/views/DocumentDecorations.scss | 3 ++ src/client/views/DocumentDecorations.tsx | 46 ++++++++++++------------------- src/client/views/InkingStroke.tsx | 33 +++++++++++++++++----- src/client/views/nodes/DocumentView.tsx | 1 + 4 files changed, 48 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 9479fd365..68e0d12d4 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -7,6 +7,9 @@ $linkGap : 3px; z-index: 2000; } .documentDecorations-inkstroke { + position: absolute; + overflow: visible; + pointer-events: none; svg:not(:root) { overflow: visible !important; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ce33f488a..3ffbb2904 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -457,23 +457,23 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight)); const useRotation = seldoc.rootDoc.type === DocumentType.INK; - const docView = seldoc.docView; - let selectedLine = null; - - if (useRotation && docView) { - const inkData = Cast(seldoc.rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }]; - const inkDoc = seldoc.layoutDoc; - const overlayInkWidth = 10; - - const { inkScaleX, inkScaleY, inkStrokeWidth } = InkingStroke.inkScaling(inkDoc, inkData, docView.props.PanelWidth(), docView.props.PanelHeight()); - - const screenInkWidth = docView.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); - const screenPts = inkData.map(point => docView.screenToLocal().inverse().transformPoint(point.X * inkScaleX, point.Y * inkScaleY)).map(p => ({ X: p[0], Y: p[1] })); - const screenTop = Math.min(...screenPts.map(p => p.Y)) - screenInkWidth[0] / 2; - const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2; - - selectedLine = InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, overlayInkWidth, overlayInkWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), - StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false); + const screenData = seldoc.ComponentView?.screenStrokeData?.(); + let selectedLine = (null); + if (screenData) { + const inkDoc = seldoc.props.Document; + const overlayWidth = 10; + selectedLine =
+ {InteractionUtils.CreatePolyline(screenData.screenPts, screenData.screenLeft, screenData.screenTop, Colors.MEDIUM_BLUE, overlayWidth, overlayWidth, + StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), + StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), + StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false)} + +
} return (
@@ -516,17 +516,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P }
-
- {selectedLine} -
+ {selectedLine} {seldoc?.Document.type === DocumentType.FONTICON ? (null) :
} diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index b8ab0c4d8..8461930bc 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -21,6 +21,7 @@ import { InkControls } from "./InkControls"; import { InkHandles } from "./InkHandles"; import { Colors } from "./global/globalEnums"; import { GestureOverlay } from "./GestureOverlay"; +import { isThisTypeNode } from "typescript"; type InkDocument = makeInterface<[typeof documentSchema]>; const InkDocument = makeInterface(documentSchema); @@ -38,6 +39,10 @@ export class InkingStroke extends ViewBoxBaseComponent { + const inkData: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? []; + const inkStrokeWidth = NumCast(this.rootDoc.strokeWidth, 1); const inkTop = Math.min(...inkData.map(p => p.Y)) - inkStrokeWidth / 2; const inkBottom = Math.max(...inkData.map(p => p.Y)) + inkStrokeWidth / 2; const inkLeft = Math.min(...inkData.map(p => p.X)) - inkStrokeWidth / 2; @@ -102,10 +108,23 @@ export class InkingStroke extends ViewBoxBaseComponent { + const inkData: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? []; + const { inkScaleX, inkScaleY, inkStrokeWidth } = this.inkScaledData(); + + const screenInkWidth = this.props.ScreenToLocalTransform().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); + const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint(point.X * inkScaleX, point.Y * inkScaleY)).map(p => ({ X: p[0], Y: p[1] })); + const screenTop = Math.min(...screenPts.map(p => p.Y)) - screenInkWidth[0] / 2; + const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2; + + return { screenPts, screenLeft, screenTop }; + } + render() { TraceMobx(); this.toggleControlButton(); @@ -114,7 +133,7 @@ export class InkingStroke extends ViewBoxBaseComponent : ""} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 745d58656..3587c1d2a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -88,6 +88,7 @@ export interface DocComponentView { setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown) playFrom?: (time: number, endTime?: number) => void; setFocus?: () => void; + screenStrokeData?: () => { screenPts: { X: number, Y: number }[], screenTop: number, screenLeft: number }; } export interface DocumentViewSharedProps { renderDepth: number; -- cgit v1.2.3-70-g09d2 From 8ab10535c0fa07247f88902089ffc23f56a22d7d Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 2 Sep 2021 15:34:15 -0400 Subject: from last --- src/client/views/InkingStroke.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 8461930bc..297b3333c 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -103,6 +103,7 @@ export class InkingStroke extends ViewBoxBaseComponent { - const inkData: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? []; - const { inkScaleX, inkScaleY, inkStrokeWidth } = this.inkScaledData(); + const { inkData, inkScaleX, inkScaleY, inkStrokeWidth } = this.inkScaledData(); const screenInkWidth = this.props.ScreenToLocalTransform().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint(point.X * inkScaleX, point.Y * inkScaleY)).map(p => ({ X: p[0], Y: p[1] })); @@ -130,25 +130,24 @@ export class InkingStroke extends ViewBoxBaseComponent : ""} -- cgit v1.2.3-70-g09d2 From 15bc374105eb7c55493d9ca6c2b12f9bf22735c9 Mon Sep 17 00:00:00 2001 From: vkalev Date: Fri, 3 Sep 2021 13:18:46 -0400 Subject: adding ComponentDecorations --- src/client/views/ComponentDecorations.scss | 0 src/client/views/ComponentDecorations.tsx | 14 + src/client/views/DocumentDecorations.scss | 631 ++++++++++++++--------------- src/client/views/DocumentDecorations.tsx | 19 - src/client/views/InkStroke.scss | 11 + src/client/views/InkingStroke.tsx | 18 +- src/client/views/MainView.tsx | 2 + src/client/views/nodes/DocumentView.tsx | 2 +- 8 files changed, 354 insertions(+), 343 deletions(-) create mode 100644 src/client/views/ComponentDecorations.scss create mode 100644 src/client/views/ComponentDecorations.tsx (limited to 'src') diff --git a/src/client/views/ComponentDecorations.scss b/src/client/views/ComponentDecorations.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/client/views/ComponentDecorations.tsx b/src/client/views/ComponentDecorations.tsx new file mode 100644 index 000000000..66f81fe4f --- /dev/null +++ b/src/client/views/ComponentDecorations.tsx @@ -0,0 +1,14 @@ +import { observer } from "mobx-react"; +import { SelectionManager } from "../util/SelectionManager"; +import './ComponentDecorations.scss'; +import React = require("react"); + +@observer +export class ComponentDecorations extends React.Component { + static Instance: ComponentDecorations; + + render() { + const seldoc = SelectionManager.Views().lastElement(); + return seldoc?.ComponentView?.componentUI?.() ?? (null); + } +} \ No newline at end of file diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 68e0d12d4..2e7142a8e 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -1,419 +1,408 @@ @import "global/globalCssVariables"; -$linkGap : 3px; +$linkGap: 3px; .documentDecorations { - position: absolute; - z-index: 2000; -} -.documentDecorations-inkstroke { - position: absolute; - overflow: visible; - pointer-events: none; - - svg:not(:root) { - overflow: visible !important; - } + position: absolute; + z-index: 2000; } .documentDecorations-container { - z-index: $docDecorations-zindex; + z-index: $docDecorations-zindex; + position: absolute; + top: 0; + left: 0; + display: grid; + grid-template-rows: 20px 8px 1fr 8px; + grid-template-columns: 8px 16px 1fr 8px 8px; + pointer-events: none; + + .documentDecorations-centerCont { + grid-column: 3; + background: none; + } + + .documentDecorations-selectorButton { + pointer-events: auto; + height: 15px; + width: 15px; + left: -20px; + top: 20px; + display: inline-block; position: absolute; - top: 0; - left: 0; - display: grid; - grid-template-rows: 20px 8px 1fr 8px; - grid-template-columns: 8px 16px 1fr 8px 8px; - pointer-events: none; - - .documentDecorations-centerCont { - grid-column: 3; - background: none; - } + opacity: 0.5; + } - .documentDecorations-selectorButton { - pointer-events: auto; - height: 15px; - width: 15px; - left: -20px; - top: 20px; - display: inline-block; - position: absolute; - opacity: 0.5; - } + .documentDecorations-radius { + pointer-events: auto; + opacity: 1; + transform: translate(10px, 10px); + grid-row: 4; + } - .documentDecorations-radius { - pointer-events: auto; - opacity: 1; - transform: translate(10px, 10px); - grid-row: 4; + .documentDecorations-topLeftResizer, + .documentDecorations-topRightResizer, + .documentDecorations-bottomLeftResizer, + .documentDecorations-bottomRightResizer, + .documentDecorations-leftResizer, + .documentDecorations-topResizer, + .documentDecorations-bottomResizer, + .documentDecorations-rightResizer { + pointer-events: auto; + background: $medium-gray; + opacity: 0.1; + &:hover { + opacity: 1; } + } - .documentDecorations-topLeftResizer, - .documentDecorations-topRightResizer, - .documentDecorations-bottomLeftResizer, - .documentDecorations-bottomRightResizer, - .documentDecorations-leftResizer, - .documentDecorations-topResizer, - .documentDecorations-bottomResizer, - .documentDecorations-rightResizer { - pointer-events: auto; - background: $medium-gray; - opacity: 0.1; - &:hover { - opacity: 1; - } - } + .documentDecorations-topLeftResizer, + .documentDecorations-leftResizer, + .documentDecorations-bottomLeftResizer { + grid-column: 1; + } - .documentDecorations-topLeftResizer, - .documentDecorations-leftResizer, - .documentDecorations-bottomLeftResizer { - grid-column: 1 - } + .documentDecorations-topResizer, + .documentDecorations-bottomResizer { + grid-column-start: 2; + grid-column-end: 5; + } - .documentDecorations-topResizer, - .documentDecorations-bottomResizer { - grid-column-start: 2; - grid-column-end: 5; - } + .documentDecorations-bottomRightResizer, + .documentDecorations-topRightResizer, + .documentDecorations-rightResizer { + grid-column-start: 5; + grid-column-end: 7; + } - .documentDecorations-bottomRightResizer, - .documentDecorations-topRightResizer, - .documentDecorations-rightResizer { - grid-column-start: 5; - grid-column-end: 7; - } + .documentDecorations-rotation, + .documentDecorations-borderRadius { + grid-column: 5; + grid-row: 4; + border-radius: 100%; + background: black; + height: 8; + right: -12; + top: 12; + position: relative; + pointer-events: all; + cursor: nwse-resize; - .documentDecorations-rotation, - .documentDecorations-borderRadius { - grid-column: 5; - grid-row: 4; - border-radius: 100%; - background: black; - height: 8; - right: -12; - top: 12; - position: relative; - pointer-events: all; - cursor: nwse-resize; - - .borderRadiusTooltip { - width: 10px; - height: 10px; - position: absolute; - } + .borderRadiusTooltip { + width: 10px; + height: 10px; + position: absolute; } - .documentDecorations-rotation { - background: transparent; - right: -15; - } - + } + .documentDecorations-rotation { + background: transparent; + right: -15; + } - .documentDecorations-topLeftResizer, - .documentDecorations-bottomRightResizer { - cursor: nwse-resize; - background: unset; - opacity: 1; - } + .documentDecorations-topLeftResizer, + .documentDecorations-bottomRightResizer { + cursor: nwse-resize; + background: unset; + opacity: 1; + } - .documentDecorations-topLeftResizer { - border-left: 2px solid; - border-top: solid 2px; - } + .documentDecorations-topLeftResizer { + border-left: 2px solid; + border-top: solid 2px; + } - .documentDecorations-bottomRightResizer { - border-right: 2px solid; - border-bottom: solid 2px; - } + .documentDecorations-bottomRightResizer { + border-right: 2px solid; + border-bottom: solid 2px; + } - .documentDecorations-topLeftResizer:hover, - .documentDecorations-bottomRightResizer:hover { - opacity: 1; - } + .documentDecorations-topLeftResizer:hover, + .documentDecorations-bottomRightResizer:hover { + opacity: 1; + } - .documentDecorations-bottomRightResizer { - grid-row: 4; - } + .documentDecorations-bottomRightResizer { + grid-row: 4; + } - .documentDecorations-topRightResizer, - .documentDecorations-bottomLeftResizer { - cursor: nesw-resize; - background: unset; - opacity: 1; - } + .documentDecorations-topRightResizer, + .documentDecorations-bottomLeftResizer { + cursor: nesw-resize; + background: unset; + opacity: 1; + } - .documentDecorations-topRightResizer { - border-right: 2px solid; - border-top: 2px solid; - } + .documentDecorations-topRightResizer { + border-right: 2px solid; + border-top: 2px solid; + } - .documentDecorations-bottomLeftResizer { - border-left: 2px solid; - border-bottom: 2px solid; - } + .documentDecorations-bottomLeftResizer { + border-left: 2px solid; + border-bottom: 2px solid; + } - .documentDecorations-topRightResizer:hover, - .documentDecorations-bottomLeftResizer:hover { - cursor: nesw-resize; - background: black; - opacity: 1; - } + .documentDecorations-topRightResizer:hover, + .documentDecorations-bottomLeftResizer:hover { + cursor: nesw-resize; + background: black; + opacity: 1; + } - .documentDecorations-topResizer, - .documentDecorations-bottomResizer { - cursor: ns-resize; - } + .documentDecorations-topResizer, + .documentDecorations-bottomResizer { + cursor: ns-resize; + } - .documentDecorations-leftResizer, - .documentDecorations-rightResizer { - cursor: ew-resize; - } + .documentDecorations-leftResizer, + .documentDecorations-rightResizer { + cursor: ew-resize; + } - .documentDecorations-contextMenu { - width: 25px; - height: calc(100% + 8px); // 8px for the height of the top resizer bar - grid-column-start: 2; - grid-column-end: 2; - pointer-events: all; - padding-left: 5px; - cursor: pointer; - } + .documentDecorations-contextMenu { + width: 25px; + height: calc(100% + 8px); // 8px for the height of the top resizer bar + grid-column-start: 2; + grid-column-end: 2; + pointer-events: all; + padding-left: 5px; + cursor: pointer; + } - .documentDecorations-titleBackground { - background: #ffffffcf; - border-radius: 8px; - width: 100%; - height: 100%; - position: absolute; - } + .documentDecorations-titleBackground { + background: #ffffffcf; + border-radius: 8px; + width: 100%; + height: 100%; + position: absolute; + } - .documentDecorations-title { - opacity: 1; - grid-column-start: 2; - grid-column-end: 4; - pointer-events: auto; - overflow: hidden; - text-align: center; - display: flex; - margin-left: 5px; - height: 22px; - position: absolute; - .documentDecorations-titleSpan { - width: 100%; - border-radius: 8px; - background: #ffffffcf; - position: absolute; - display: inline-block; - cursor: move; - } + .documentDecorations-title { + opacity: 1; + grid-column-start: 2; + grid-column-end: 4; + pointer-events: auto; + overflow: hidden; + text-align: center; + display: flex; + margin-left: 5px; + height: 22px; + position: absolute; + .documentDecorations-titleSpan { + width: 100%; + border-radius: 8px; + background: #ffffffcf; + position: absolute; + display: inline-block; + cursor: move; } + } - .focus-visible { - margin-left: 0px; - } + .focus-visible { + margin-left: 0px; + } } - .documentDecorations-iconifyButton { - opacity: 1; - grid-column-start: 4; - grid-column-end: 4; - pointer-events: all; - right: 0; - cursor: pointer; - position: absolute; - width: 20px; + opacity: 1; + grid-column-start: 4; + grid-column-end: 4; + pointer-events: all; + right: 0; + cursor: pointer; + position: absolute; + width: 20px; } .documentDecorations-openButton { - display: flex; - align-items: center; - opacity: 1; - grid-column-start: 5; - grid-column-end: 5; - pointer-events: all; - cursor: pointer; + display: flex; + align-items: center; + opacity: 1; + grid-column-start: 5; + grid-column-end: 5; + pointer-events: all; + cursor: pointer; } .documentDecorations-closeButton { - display: flex; - align-items: center; - opacity: 1; - grid-column-start: 1; - grid-column-end: 3; - pointer-events: all; - cursor: pointer; - - >svg { - margin: 0; - } + display: flex; + align-items: center; + opacity: 1; + grid-column-start: 1; + grid-column-end: 3; + pointer-events: all; + cursor: pointer; + + > svg { + margin: 0; + } } .documentDecorations-background { - background: lightblue; - position: absolute; - opacity: 0.1; + background: lightblue; + position: absolute; + opacity: 0.1; } .linkFlyout { - grid-column: 2/4; + grid-column: 2/4; } .linkButton-empty:hover { - background: $medium-gray; - transform: scale(1.05); - cursor: pointer; + background: $medium-gray; + transform: scale(1.05); + cursor: pointer; } .linkButton-nonempty:hover { - background: $medium-gray; - transform: scale(1.05); - cursor: pointer; + background: $medium-gray; + transform: scale(1.05); + cursor: pointer; } .link-button-container { - border-radius: 10px; - width: max-content; - height: auto; - display: flex; - flex-direction: row; - z-index: 998; - position: absolute; - justify-content: center; - align-items: center; - gap: 5px; - background: $medium-gray; + border-radius: 10px; + width: max-content; + height: auto; + display: flex; + flex-direction: row; + z-index: 998; + position: absolute; + justify-content: center; + align-items: center; + gap: 5px; + background: $medium-gray; } .linkButtonWrapper { - pointer-events: auto; - padding-right: 5px; - width: 25px; + pointer-events: auto; + padding-right: 5px; + width: 25px; } .linkButton-linker { - height: 20px; - width: 20px; - text-align: center; - border-radius: 50%; - pointer-events: auto; - color: $dark-gray; - border: $dark-gray 1px solid; + height: 20px; + width: 20px; + text-align: center; + border-radius: 50%; + pointer-events: auto; + color: $dark-gray; + border: $dark-gray 1px solid; } .linkButton-linker:hover { - cursor: pointer; - transform: scale(1.05); + cursor: pointer; + transform: scale(1.05); } .linkButton-empty, .linkButton-nonempty { - height: 20px; - width: 20px; - border-radius: 50%; - opacity: 0.9; - pointer-events: auto; - background-color: $dark-gray; - color: $white; - text-transform: uppercase; - letter-spacing: 2px; - font-size: 75%; - transition: transform 0.2s; - text-align: center; - display: flex; - justify-content: center; - align-items: center; - - &:hover { - background: $medium-gray; - transform: scale(1.05); - cursor: pointer; - } + height: 20px; + width: 20px; + border-radius: 50%; + opacity: 0.9; + pointer-events: auto; + background-color: $dark-gray; + color: $white; + text-transform: uppercase; + letter-spacing: 2px; + font-size: 75%; + transition: transform 0.2s; + text-align: center; + display: flex; + justify-content: center; + align-items: center; + + &:hover { + background: $medium-gray; + transform: scale(1.05); + cursor: pointer; + } } .templating-menu { - position: absolute; - pointer-events: auto; - text-transform: uppercase; - letter-spacing: 2px; - font-size: 75%; - transition: transform 0.2s; - text-align: center; - display: flex; - justify-content: center; - align-items: center; + position: absolute; + pointer-events: auto; + text-transform: uppercase; + letter-spacing: 2px; + font-size: 75%; + transition: transform 0.2s; + text-align: center; + display: flex; + justify-content: center; + align-items: center; } .documentdecorations-icon { - margin: 0px; + margin: 0px; } .templating-button, .docDecs-tagButton { - width: 20px; - height: 20px; - border-radius: 50%; - opacity: 0.9; - font-size: 14; - background-color: $dark-gray; - color: $white; - text-align: center; - cursor: pointer; - - &:hover { - background: $medium-gray; - transform: scale(1.05); - } + width: 20px; + height: 20px; + border-radius: 50%; + opacity: 0.9; + font-size: 14; + background-color: $dark-gray; + color: $white; + text-align: center; + cursor: pointer; + + &:hover { + background: $medium-gray; + transform: scale(1.05); + } } .documentDecorations-darkScheme { - background: dimgray; + background: dimgray; } #template-list { - position: absolute; - top: 25px; - left: 0px; - width: max-content; - font-family: $sans-serif; - font-size: 12px; - background-color: $light-gray; - padding: 2px 12px; - list-style: none; - - .templateToggle, - .chromeToggle { - text-align: left; - } + position: absolute; + top: 25px; + left: 0px; + width: max-content; + font-family: $sans-serif; + font-size: 12px; + background-color: $light-gray; + padding: 2px 12px; + list-style: none; + + .templateToggle, + .chromeToggle { + text-align: left; + } - input { - margin-right: 10px; - } + input { + margin-right: 10px; + } } @-moz-keyframes spin { - 100% { - -moz-transform: rotate(360deg); - } + 100% { + -moz-transform: rotate(360deg); + } } @-webkit-keyframes spin { - 100% { - -webkit-transform: rotate(360deg); - } + 100% { + -webkit-transform: rotate(360deg); + } } @keyframes spin { - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } } @keyframes shadow-pulse { - 0% { - box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.8); - } + 0% { + box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.8); + } - 100% { - box-shadow: 0 0 0 10px rgba(0, 255, 0, 0); - } -} \ No newline at end of file + 100% { + box-shadow: 0 0 0 10px rgba(0, 255, 0, 0); + } +} diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3ffbb2904..2348c897b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -457,24 +457,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight)); const useRotation = seldoc.rootDoc.type === DocumentType.INK; - const screenData = seldoc.ComponentView?.screenStrokeData?.(); - let selectedLine = (null); - if (screenData) { - const inkDoc = seldoc.props.Document; - const overlayWidth = 10; - selectedLine =
- {InteractionUtils.CreatePolyline(screenData.screenPts, screenData.screenLeft, screenData.screenTop, Colors.MEDIUM_BLUE, overlayWidth, overlayWidth, - StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), - StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), - StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false)} - -
- } return (
}
- {selectedLine} {seldoc?.Document.type === DocumentType.FONTICON ? (null) :
} diff --git a/src/client/views/InkStroke.scss b/src/client/views/InkStroke.scss index 812a79bd5..8edefa07b 100644 --- a/src/client/views/InkStroke.scss +++ b/src/client/views/InkStroke.scss @@ -1,3 +1,14 @@ +.inkstroke-UI { + // transform-origin: top left; + position: absolute; + overflow: visible; + pointer-events: none; + + svg:not(:root) { + overflow: visible !important; + } +} + .inkStroke { mix-blend-mode: multiply; stroke-linejoin: round; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 297b3333c..41fbe0d55 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -114,7 +114,7 @@ export class InkingStroke extends ViewBoxBaseComponent { + componentUI = () => { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth } = this.inkScaledData(); const screenInkWidth = this.props.ScreenToLocalTransform().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); @@ -122,7 +122,21 @@ export class InkingStroke extends ViewBoxBaseComponent p.Y)) - screenInkWidth[0] / 2; const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2; - return { screenPts, screenLeft, screenTop }; + const inkDoc = this.props.Document; + + const overlayWidth = 5; + return
+ {InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, overlayWidth, overlayWidth, + StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), + StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), + StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false)} + +
} render() { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 1ce363b0a..b81459075 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -39,6 +39,7 @@ import { CollectionViewType } from './collections/CollectionView'; import { ContextMenu } from './ContextMenu'; import { DictationOverlay } from './DictationOverlay'; import { DocumentDecorations } from './DocumentDecorations'; +import { ComponentDecorations } from './ComponentDecorations'; import { GestureOverlay } from './GestureOverlay'; import { MENU_PANEL_WIDTH, SEARCH_PANEL_HEIGHT } from './global/globalCssVariables.scss'; import { KeyManager } from './GlobalKeyHandler'; @@ -594,6 +595,7 @@ export class MainView extends React.Component { + {this.search} {LinkDescriptionPopup.descriptionPopup ? : null} {DocumentLinksButton.LinkEditorDocView ? : (null)} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3587c1d2a..4e6ed40d1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -88,7 +88,7 @@ export interface DocComponentView { setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown) playFrom?: (time: number, endTime?: number) => void; setFocus?: () => void; - screenStrokeData?: () => { screenPts: { X: number, Y: number }[], screenTop: number, screenLeft: number }; + componentUI?: () => JSX.Element; } export interface DocumentViewSharedProps { renderDepth: number; -- cgit v1.2.3-70-g09d2 From da6bc0d484c5d917dca38178f99f1dfc14d2d0ec Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 3 Sep 2021 14:58:49 -0400 Subject: fixed selection stroke offset --- src/client/views/InkingStroke.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 41fbe0d55..634cb0dfd 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -118,23 +118,22 @@ export class InkingStroke extends ViewBoxBaseComponent this.props.ScreenToLocalTransform().inverse().transformPoint(point.X * inkScaleX, point.Y * inkScaleY)).map(p => ({ X: p[0], Y: p[1] })); + const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint(point.X, point.Y)).map(p => ({ X: p[0], Y: p[1] })); const screenTop = Math.min(...screenPts.map(p => p.Y)) - screenInkWidth[0] / 2; const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2; const inkDoc = this.props.Document; - + const overlayWidth = 5; + const screenOrigin = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); return
{InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, overlayWidth, overlayWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), - StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false)} + StrCast(inkDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false)}
} -- cgit v1.2.3-70-g09d2 From 85345138396771a30f9d0e7a26837edc0a972bee Mon Sep 17 00:00:00 2001 From: vkalev Date: Fri, 3 Sep 2021 16:29:20 -0400 Subject: selection line width fix --- src/client/views/InkingStroke.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 634cb0dfd..90eb52dd2 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -124,13 +124,13 @@ export class InkingStroke extends ViewBoxBaseComponent - {InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, overlayWidth, overlayWidth, + {InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, screenInkWidth[0], overlayWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false)} -- cgit v1.2.3-70-g09d2 From 9a4bd3ca5dbe192eec20bf405a9904ef8b546de6 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 4 Sep 2021 00:46:41 -0400 Subject: added top/left clip bounds to ink decorations --- src/client/views/ComponentDecorations.tsx | 4 ++-- src/client/views/InkingStroke.tsx | 3 ++- src/client/views/MainView.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/ComponentDecorations.tsx b/src/client/views/ComponentDecorations.tsx index 66f81fe4f..66d1bd63d 100644 --- a/src/client/views/ComponentDecorations.tsx +++ b/src/client/views/ComponentDecorations.tsx @@ -4,11 +4,11 @@ import './ComponentDecorations.scss'; import React = require("react"); @observer -export class ComponentDecorations extends React.Component { +export class ComponentDecorations extends React.Component<{ boundsTop: number, boundsLeft: number }, { value: string }> { static Instance: ComponentDecorations; render() { const seldoc = SelectionManager.Views().lastElement(); - return seldoc?.ComponentView?.componentUI?.() ?? (null); + return seldoc?.ComponentView?.componentUI?.(this.props.boundsLeft, this.props.boundsTop) ?? (null); } } \ No newline at end of file diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 90eb52dd2..e713cedee 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -114,7 +114,7 @@ export class InkingStroke extends ViewBoxBaseComponent { + componentUI = (boundsLeft: number, boundsTop: number) => { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth } = this.inkScaledData(); const screenInkWidth = this.props.ScreenToLocalTransform().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); @@ -129,6 +129,7 @@ export class InkingStroke extends ViewBoxBaseComponent {InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, screenInkWidth[0], overlayWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index b81459075..f03124f0d 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -83,7 +83,7 @@ export class MainView extends React.Component { @observable private _sidebarContent: any = this.userDoc?.sidebar; @observable private _flyoutWidth: number = 0; - @computed private get topOffset() { return Number(SEARCH_PANEL_HEIGHT.replace("px", "")); } //TODO remove + @computed private get topOffset() { return 35 + Number(SEARCH_PANEL_HEIGHT.replace("px", "")); } //TODO remove @computed private get leftOffset() { return this.menuPanelWidth() - 2; } @computed private get userDoc() { return Doc.UserDoc(); } @computed private get darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkScheme); } @@ -595,7 +595,7 @@ export class MainView extends React.Component { - + {this.search} {LinkDescriptionPopup.descriptionPopup ? : null} {DocumentLinksButton.LinkEditorDocView ? : (null)} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4e6ed40d1..a9b303294 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -88,7 +88,7 @@ export interface DocComponentView { setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown) playFrom?: (time: number, endTime?: number) => void; setFocus?: () => void; - componentUI?: () => JSX.Element; + componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element; } export interface DocumentViewSharedProps { renderDepth: number; -- cgit v1.2.3-70-g09d2 From 02a6d5404f23ffb486e183d68d3af71728e85f09 Mon Sep 17 00:00:00 2001 From: kimdahey Date: Mon, 13 Sep 2021 18:03:56 -0400 Subject: working on control points --- src/client/views/InkControls.tsx | 4 ++-- src/client/views/InkingStroke.tsx | 26 +++++++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx index 6213a4075..46377380a 100644 --- a/src/client/views/InkControls.tsx +++ b/src/client/views/InkControls.tsx @@ -121,8 +121,8 @@ export class InkControls extends React.Component { { diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index e713cedee..771419937 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -126,6 +126,11 @@ export class InkingStroke extends ViewBoxBaseComponent + + + : ""}
} @@ -161,8 +179,6 @@ export class InkingStroke extends ViewBoxBaseComponent - : ""} + : ""} */} ); } -- cgit v1.2.3-70-g09d2 From fc68dcd02c36c41813a5aecb37602fd9a7cdaebe Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 09:14:56 -0400 Subject: fixed crash for loading some images (e.g, .tiff) --- src/server/DashUploadUtils.ts | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 549dc0396..7b83d09ef 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -242,18 +242,23 @@ export namespace DashUploadUtils { const { headers } = (await new Promise((resolve, reject) => { request.head(resolvedUrl, (error, res) => error ? reject(error) : resolve(res)); }).catch(error => console.error(error))); - // Compute the native width and height ofthe image with an npm module - const { width: nativeWidth, height: nativeHeight }: RequestedImageSize = await requestImageSize(resolvedUrl); - // Bundle up the information into an object - return { - source, - contentSize: parseInt(headers[size]), - contentType: headers[type], - nativeWidth, - nativeHeight, - filename, - ...results - }; + try { + // Compute the native width and height ofthe image with an npm module + const { width: nativeWidth, height: nativeHeight } = await requestImageSize(resolvedUrl); + // Bundle up the information into an object + return { + source, + contentSize: parseInt(headers[size]), + contentType: headers[type], + nativeWidth, + nativeHeight, + filename, + ...results + }; + } catch (e) { + console.log(e); + return e; + } }; /** -- cgit v1.2.3-70-g09d2 From 43fb727413538036a81d9f2104dd0133f19e0e87 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 14:37:30 -0400 Subject: put handles in right place for ink. --- src/client/views/InkStroke.scss | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/client/views/InkStroke.scss b/src/client/views/InkStroke.scss index 8edefa07b..53d27cd24 100644 --- a/src/client/views/InkStroke.scss +++ b/src/client/views/InkStroke.scss @@ -6,6 +6,9 @@ svg:not(:root) { overflow: visible !important; + position: absolute; + left:0; + top:0; } } -- cgit v1.2.3-70-g09d2 From c316b836b5fae84546eac15ae74833d31cb1318d Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 15:09:35 -0400 Subject: fixed handle size/placement for ink editing. --- src/client/views/InkControls.tsx | 14 +++++++------- src/client/views/InkHandles.tsx | 8 ++++---- src/client/views/InkingStroke.tsx | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx index 46377380a..b62239c4f 100644 --- a/src/client/views/InkControls.tsx +++ b/src/client/views/InkControls.tsx @@ -96,8 +96,8 @@ export class InkControls extends React.Component { } } const addedPoints = this.props.addedPoints; - const [left, top, scaleX, scaleY, strokeWidth] = this.props.format; - + const [left, top, scaleX, scaleY, strokeWidth, screenSpaceLineWidth] = this.props.format; + const rectHdlSize = this._overControl === i ? screenSpaceLineWidth * 6 : screenSpaceLineWidth * 4; return ( <> {addedPoints.map((pts, i) => @@ -119,11 +119,11 @@ export class InkControls extends React.Component { {controlPoints.map((control, i) => { this.changeCurrPoint(control.I); diff --git a/src/client/views/InkHandles.tsx b/src/client/views/InkHandles.tsx index b9f75f8d7..4e3a842d0 100644 --- a/src/client/views/InkHandles.tsx +++ b/src/client/views/InkHandles.tsx @@ -83,7 +83,7 @@ export class InkHandles extends React.Component { handleLines.push({ X1: data[i].X, Y1: data[i].Y, X2: data[i + 1].X, Y2: data[i + 1].Y, X3: data[i + 3].X, Y3: data[i + 3].Y, dot1: i + 1, dot2: i + 2 }); } } - const [left, top, scaleX, scaleY, strokeWidth] = this.props.format; + const [left, top, scaleX, scaleY, strokeWidth, screenSpaceLineWidth] = this.props.format; return ( <> @@ -92,7 +92,7 @@ export class InkHandles extends React.Component { this.onHandleDown(e, pts.I)} @@ -108,7 +108,7 @@ export class InkHandles extends React.Component { x2={(pts.X2 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} y2={(pts.Y2 - top - strokeWidth / 2) * scaleY + strokeWidth / 2} stroke={Colors.MEDIUM_BLUE} - strokeWidth={strokeWidth / 4} + strokeWidth={screenSpaceLineWidth} display={(pts.dot1 === formatInstance._currentPoint || pts.dot2 === formatInstance._currentPoint) ? "inherit" : "none"} /> { x2={(pts.X3 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} y2={(pts.Y3 - top - strokeWidth / 2) * scaleY + strokeWidth / 2} stroke={Colors.MEDIUM_BLUE} - strokeWidth={strokeWidth / 4} + strokeWidth={screenSpaceLineWidth} display={(pts.dot1 === formatInstance._currentPoint || pts.dot2 === formatInstance._currentPoint) ? "inherit" : "none"} /> )} diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 771419937..06d15a108 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -146,12 +146,12 @@ export class InkingStroke extends ViewBoxBaseComponent : ""}
-- cgit v1.2.3-70-g09d2 From d1735ffc305ec65f896a16b794fb3da8383d2287 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 15:09:47 -0400 Subject: from last --- src/client/views/InkControls.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx index b62239c4f..b97075489 100644 --- a/src/client/views/InkControls.tsx +++ b/src/client/views/InkControls.tsx @@ -123,7 +123,8 @@ export class InkControls extends React.Component { y={(control.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2 - rectHdlSize / 2} height={rectHdlSize} width={rectHdlSize} - strokeWidth={screenSpaceLineWidth / 2} stroke={Colors.MEDIUM_BLUE} + strokeWidth={screenSpaceLineWidth / 2} + stroke={Colors.MEDIUM_BLUE} fill={formatInstance?._currentPoint === control.I ? Colors.MEDIUM_BLUE : Colors.WHITE} onPointerDown={(e) => { this.changeCurrPoint(control.I); -- cgit v1.2.3-70-g09d2 From d22dd9550a2ae4de98b6b56c0f57b9de9d6122bd Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 15:10:46 -0400 Subject: Update InkControls.tsx fixed error with ink handles. --- src/client/views/InkControls.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx index b97075489..e4861c086 100644 --- a/src/client/views/InkControls.tsx +++ b/src/client/views/InkControls.tsx @@ -97,7 +97,7 @@ export class InkControls extends React.Component { } const addedPoints = this.props.addedPoints; const [left, top, scaleX, scaleY, strokeWidth, screenSpaceLineWidth] = this.props.format; - const rectHdlSize = this._overControl === i ? screenSpaceLineWidth * 6 : screenSpaceLineWidth * 4; + const rectHdlSize = (i: number) => this._overControl === i ? screenSpaceLineWidth * 6 : screenSpaceLineWidth * 4; return ( <> {addedPoints.map((pts, i) => @@ -119,10 +119,10 @@ export class InkControls extends React.Component { {controlPoints.map((control, i) => Date: Tue, 14 Sep 2021 15:31:31 -0400 Subject: addition of tooltips and minor formatting improvements in search panel --- src/client/views/search/SearchBox.scss | 6 ++++-- src/client/views/search/SearchBox.tsx | 28 +++++++++++++++++----------- 2 files changed, 21 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index 2586ef2ee..e8865b918 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -78,8 +78,10 @@ .searchBox-result-title { display: relative; float: left; - width: calc(100% - 60px); + width: calc(100% - 45px); text-align: left; + overflow: hidden; + text-overflow: ellipsis; } .searchBox-result-type { @@ -87,7 +89,7 @@ margin-top: 6px; display: relative; float: right; - width: 60px; + width: 45px; text-align: right; color: #222; } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index e70b2bc19..dbd641550 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -13,6 +13,7 @@ import { FieldView, FieldViewProps } from '../nodes/FieldView'; import "./SearchBox.scss"; import { DocumentManager } from '../../util/DocumentManager'; import { DocUtils } from '../../documents/Documents'; +import { Tooltip } from "@material-ui/core"; export const searchSchema = createSchema({ Document: Doc @@ -299,20 +300,25 @@ export class SearchBox extends ViewBoxBaseComponent this.makeLink(result[0]) : () => this.onResultClick(result[0])} className={className}> -
- {result[0].title} -
-
- {SearchBox.formatType(StrCast(result[0].type))} +
{title}
}> +
this.makeLink(result[0]) : () => this.onResultClick(result[0])} className={className}> +
+ {title} +
+
+ {formattedType} +
+
+ {result[1].join(", ")} +
-
- {result[1].join(", ")} -
-
+ ); } @@ -327,7 +333,7 @@ export class SearchBox extends ViewBoxBaseComponent {this.selectOptions} } - + e.key === "Enter" ? this.submitSearch() : null} type="text" placeholder="Search..." id="search-input" className="searchBox-input" style={{ width: isLinkSearch ? "100%" : undefined, borderRadius: isLinkSearch ? "5px" : undefined }} ref={this._inputRef} />
-- cgit v1.2.3-70-g09d2 From abc5f96945fc0716fb1ccb4c99005bc7b7473086 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 15:49:21 -0400 Subject: fixed adding a new point on an ink stroke --- src/client/views/InkControls.tsx | 119 ++++++++++++++++++++------------------ src/client/views/InkHandles.tsx | 15 +++-- src/client/views/InkingStroke.tsx | 25 ++++---- 3 files changed, 83 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx index e4861c086..4df7ee813 100644 --- a/src/client/views/InkControls.tsx +++ b/src/client/views/InkControls.tsx @@ -1,20 +1,22 @@ import React = require("react"); -import { observable, action } from "mobx"; +import { action, observable } from "mobx"; import { observer } from "mobx-react"; -import { InkStrokeProperties } from "./InkStrokeProperties"; -import { setupMoveUpEvents, emptyFunction } from "../../Utils"; -import { UndoManager } from "../util/UndoManager"; -import { ControlPoint, InkData, PointData } from "../../fields/InkField"; -import { Transform } from "../util/Transform"; -import { Colors } from "./global/globalEnums"; import { Doc } from "../../fields/Doc"; +import { ControlPoint, InkData, PointData } from "../../fields/InkField"; import { listSpec } from "../../fields/Schema"; import { Cast } from "../../fields/Types"; +import { setupMoveUpEvents } from "../../Utils"; +import { Transform } from "../util/Transform"; +import { UndoManager } from "../util/UndoManager"; +import { Colors } from "./global/globalEnums"; +import { InkStrokeProperties } from "./InkStrokeProperties"; export interface InkControlProps { inkDoc: Doc; - data: InkData; - addedPoints: PointData[]; + inkCtrlPoints: InkData; + screenCtrlPoints: InkData; + inkStrokeSamplePts: PointData[]; + screenStrokeSamplePoints: PointData[]; format: number[]; ScreenToLocalTransform: () => Transform; } @@ -87,57 +89,60 @@ export class InkControls extends React.Component { if (!formatInstance) return (null); // Accessing the current ink's data and extracting all control points. - const data = this.props.data; - const controlPoints: ControlPoint[] = []; - if (data.length >= 4) { - for (let i = 0; i <= data.length - 4; i += 4) { - controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i }); - controlPoints.push({ X: data[i + 3].X, Y: data[i + 3].Y, I: i + 3 }); - } + const scrData = this.props.screenCtrlPoints; + const sreenCtrlPoints: ControlPoint[] = []; + for (let i = 0; i <= scrData.length - 4; i += 4) { + sreenCtrlPoints.push({ X: scrData[i].X, Y: scrData[i].Y, I: i }); + sreenCtrlPoints.push({ X: scrData[i + 3].X, Y: scrData[i + 3].Y, I: i + 3 }); } - const addedPoints = this.props.addedPoints; + + const inkData = this.props.inkCtrlPoints; + const inkCtrlPts: ControlPoint[] = []; + for (let i = 0; i <= inkData.length - 4; i += 4) { + inkCtrlPts.push({ X: inkData[i].X, Y: inkData[i].Y, I: i }); + inkCtrlPts.push({ X: inkData[i + 3].X, Y: inkData[i + 3].Y, I: i + 3 }); + } + const [left, top, scaleX, scaleY, strokeWidth, screenSpaceLineWidth] = this.props.format; const rectHdlSize = (i: number) => this._overControl === i ? screenSpaceLineWidth * 6 : screenSpaceLineWidth * 4; - return ( - <> - {addedPoints.map((pts, i) => - - { formatInstance?.addPoints(pts.X, pts.Y, addedPoints, i, controlPoints); }} - onMouseEnter={() => this.onEnterAddPoint(i)} - onMouseLeave={this.onLeaveAddPoint} - pointerEvents="all" - cursor="all-scroll" - /> - - )} - {controlPoints.map((control, i) => - - { - this.changeCurrPoint(control.I); - this.onControlDown(e, control.I); - }} - onMouseEnter={() => this.onEnterControl(i)} - onMouseLeave={this.onLeaveControl} - pointerEvents="all" - cursor="default" - /> - - )} - + return ( + {/* should really have just one circle here that represents the neqraest point on the stroke to the users hover point. + This points should be passed as a prop from InkingStroke's UI which should set it in its onPointerOver method */} + {this.props.screenStrokeSamplePoints.map((pts, i) => + formatInstance?.addPoints(this.props.inkStrokeSamplePts[i].X, this.props.inkStrokeSamplePts[i].Y, this.props.inkStrokeSamplePts, i, inkCtrlPts)} + onMouseEnter={() => this.onEnterAddPoint(i)} + onMouseLeave={this.onLeaveAddPoint} + pointerEvents="all" + cursor="all-scroll" + /> + )} + {sreenCtrlPoints.map((control, i) => + { + this.changeCurrPoint(control.I); + this.onControlDown(e, control.I); + }} + onMouseEnter={() => this.onEnterControl(i)} + onMouseLeave={this.onLeaveControl} + pointerEvents="all" + cursor="default" + /> + )} + ); } } \ No newline at end of file diff --git a/src/client/views/InkHandles.tsx b/src/client/views/InkHandles.tsx index 4e3a842d0..afe94cdfb 100644 --- a/src/client/views/InkHandles.tsx +++ b/src/client/views/InkHandles.tsx @@ -1,17 +1,16 @@ import React = require("react"); -import { observable, action } from "mobx"; +import { action } from "mobx"; import { observer } from "mobx-react"; -import { InkStrokeProperties } from "./InkStrokeProperties"; -import { setupMoveUpEvents, emptyFunction } from "../../Utils"; -import { UndoManager } from "../util/UndoManager"; -import { InkData, HandlePoint, HandleLine } from "../../fields/InkField"; -import { Transform } from "../util/Transform"; import { Doc } from "../../fields/Doc"; -import { listSpec } from "../../fields/Schema"; +import { HandleLine, HandlePoint, InkData } from "../../fields/InkField"; import { List } from "../../fields/List"; +import { listSpec } from "../../fields/Schema"; import { Cast } from "../../fields/Types"; +import { emptyFunction, setupMoveUpEvents } from "../../Utils"; +import { Transform } from "../util/Transform"; +import { UndoManager } from "../util/UndoManager"; import { Colors } from "./global/globalEnums"; -import { GestureOverlay } from "./GestureOverlay"; +import { InkStrokeProperties } from "./InkStrokeProperties"; export interface InkHandlesProps { inkDoc: Doc; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 06d15a108..768808569 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -115,28 +115,29 @@ export class InkingStroke extends ViewBoxBaseComponent { - const { inkData, inkScaleX, inkScaleY, inkStrokeWidth } = this.inkScaledData(); + const inkDoc = this.props.Document; + const screenSpaceCenterlineStrokeWidth = 3; // the width of the blue line widget that shows the centerline of the ink stroke + const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const screenInkWidth = this.props.ScreenToLocalTransform().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint(point.X, point.Y)).map(p => ({ X: p[0], Y: p[1] })); const screenTop = Math.min(...screenPts.map(p => p.Y)) - screenInkWidth[0] / 2; const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2; - - const inkDoc = this.props.Document; - - const overlayWidth = 3; const screenOrigin = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - const addedPoints = InteractionUtils.CreatePoints(inkData, screenLeft, screenTop, StrCast(inkDoc.strokeColor, "none"), screenInkWidth[0], overlayWidth, + const screenSpaceSamplePoints = InteractionUtils.CreatePoints(screenPts, screenLeft, screenTop, StrCast(inkDoc.strokeColor, "none"), screenInkWidth[0], screenSpaceCenterlineStrokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", this.props.isSelected() && inkStrokeWidth <= 5, false); + const inkSpaceSamplePoints = InteractionUtils.CreatePoints(inkData, inkLeft, inkTop, StrCast(inkDoc.strokeColor, "none"), inkStrokeWidth, screenSpaceCenterlineStrokeWidth, + StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker), + StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), 1, 1, "", "none", this.props.isSelected() && inkStrokeWidth <= 5, false); return
- {InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, screenInkWidth[0], overlayWidth, + {InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, screenInkWidth[0], screenSpaceCenterlineStrokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"), StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false)} @@ -144,14 +145,16 @@ export class InkingStroke extends ViewBoxBaseComponent : ""}
-- cgit v1.2.3-70-g09d2 From f4b3781cf2250477482d8260e7137d9cbdfcb8e4 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 16:44:35 -0400 Subject: fixed height of maincontent. fixed warnings. --- src/client/views/MainView.tsx | 19 +++++++++++-------- .../collectionSchema/CollectionSchemaCells.tsx | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 39a14285a..b102c9a1f 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -11,7 +11,6 @@ import * as ReactDOM from 'react-dom'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { List } from '../../fields/List'; import { PrefetchProxy } from '../../fields/Proxy'; -import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, PromiseValue, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils'; @@ -37,7 +36,6 @@ import { CollectionLinearView } from './collections/collectionLinear'; import { CollectionMenu } from './collections/CollectionMenu'; import { CollectionViewType } from './collections/CollectionView'; import "./collections/TreeView.scss"; -import { ComponentDecorations } from './ComponentDecorations'; import { ContextMenu } from './ContextMenu'; import { DictationOverlay } from './DictationOverlay'; import { DocumentDecorations } from './DocumentDecorations'; @@ -50,11 +48,9 @@ import { LightboxView } from './LightboxView'; import { LinkMenu } from './linking/LinkMenu'; import "./MainView.scss"; import { AudioBox } from './nodes/AudioBox'; -import { ButtonType } from './nodes/button/FontIconBox'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { DocumentView } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; -import { RichTextMenu } from './nodes/formattedText/RichTextMenu'; import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview } from './nodes/LinkDocPreview'; import { RadialMenu } from './nodes/RadialMenu'; @@ -66,6 +62,10 @@ import { PreviewCursor } from './PreviewCursor'; import { PropertiesView } from './PropertiesView'; import { DashboardStyleProvider, DefaultStyleProvider } from './StyleProvider'; import { TopBar } from './topbar/TopBar'; +import { RichTextMenu } from './nodes/formattedText/RichTextMenu'; +import { ScriptField } from '../../fields/ScriptField'; +import { ButtonType } from './nodes/button/FontIconBox'; +import { ComponentDecorations } from './ComponentDecorations'; const _global = (window /* browser */ || global /* node */) as any; @observer @@ -247,7 +247,10 @@ export class MainView extends React.Component { if (!await this.userDoc.myFilesystem) { this.userDoc.myFileOrphans = Docs.Create.TreeDocument([], { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true }); const newFolder = ScriptField.MakeFunction(`createNewFolder()`, { scriptContext: "any" })!; - const newFolderButton: Doc = Docs.Create.FontIconDocument({ onClick: newFolder, _forceActive: true, toolTip: "New folder", _stayInCollection: true, _hideContextMenu: true, title: "New folder", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New folder", icon: "folder-plus", system: true }); + const newFolderButton: Doc = Docs.Create.FontIconDocument({ + onClick: newFolder, _forceActive: true, toolTip: "New folder", _stayInCollection: true, _hideContextMenu: true, title: "New folder", + btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New folder", icon: "folder-plus", system: true + }); this.userDoc.myFilesystem = new PrefetchProxy(Docs.Create.TreeDocument([this.userDoc.myFileOrphans as Doc], { title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100, treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", @@ -450,7 +453,7 @@ export class MainView extends React.Component { r && new _global.ResizeObserver(action(() => { this._panelWidth = r.getBoundingClientRect().width; this._panelHeight = r.getBoundingClientRect().height; })).observe(r); }} style={{ color: this.darkScheme ? "rgb(205,205,205)" : "black", - height: `calc(100% - ${this.topOffset}px)`, + height: `calc(100% - ${this.topOffset - 35}px)`, width: "100%", }} > {this.mainInnerContent} @@ -495,8 +498,8 @@ export class MainView extends React.Component { rootSelected={returnTrue} bringToFront={emptyFunction} select={emptyFunction} - isContentActive={returnFalse} isAnyChildContentActive={returnFalse} + isContentActive={returnFalse} isSelected={returnFalse} docViewPath={returnEmptyDoclist} moveDocument={this.moveButtonDoc} @@ -604,7 +607,7 @@ export class MainView extends React.Component { - + {/* 27 comes form lm.config.defaultConfig.dimensions.headerHeight in goldenlayout.js */} {this.topbar} {LinkDescriptionPopup.descriptionPopup ? : null} {DocumentLinksButton.LinkEditorDocView ? : (null)} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index fd99abce5..ed196349e 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -293,12 +293,12 @@ export class CollectionSchemaCell extends React.Component { } } const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = value.length !== value.length || value.length - 2 !== value.length; + const changeMade = value.length - 2 !== value.length; script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); // handle booleans } else if (inputIsBool) { const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = value.length !== value.length || value.length - 2 !== value.length; + const changeMade = value.length - 2 !== value.length; script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); } } -- cgit v1.2.3-70-g09d2 From 7ab2011d3b6bb7bb2e945265d4ff97983a5a1f38 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 19:13:34 -0400 Subject: fixed right-click context menu for Windows. --- src/Utils.ts | 30 +++++++++++++++++------------- src/client/views/nodes/DocumentView.tsx | 9 +++++++-- 2 files changed, 24 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/Utils.ts b/src/Utils.ts index ddc16dceb..6eacd8296 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -552,19 +552,23 @@ export function simulateMouseClick(element: Element | null | undefined, x: numbe screenY: sy, }))); - rightClick && element.dispatchEvent( - new MouseEvent("contextmenu", { - view: window, - bubbles: true, - cancelable: true, - button: 2, - clientX: x, - clientY: y, - movementX: 0, - movementY: 0, - screenX: sx, - screenY: sy, - })); + if (rightClick) { + const me = + new MouseEvent("contextmenu", { + view: window, + bubbles: true, + cancelable: true, + button: 2, + clientX: x, + clientY: y, + movementX: 0, + movementY: 0, + screenX: sx, + screenY: sy, + }); + (me as any).dash = true; + element.dispatchEvent(me); + } } export function lightOrDark(color: any) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5ef49bd3b..b680fcf3b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -672,7 +672,7 @@ export class DocumentViewInternal extends DocComponent setTimeout(() => { DocumentViewInternal.SelectAfterContextMenu && !this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => { @@ -680,7 +680,12 @@ export class DocumentViewInternal extends DocComponent Date: Tue, 14 Sep 2021 22:27:17 -0400 Subject: refactored a bunch of names in MainView. Fixed scrolling in left menu flyout treeview panels. --- src/client/views/MainView.scss | 62 +--------- src/client/views/MainView.tsx | 126 +++++++++++---------- src/client/views/collections/CollectionMenu.tsx | 34 +++--- .../views/collections/CollectionTreeView.tsx | 68 +++++------ src/client/views/collections/TreeView.tsx | 2 +- src/client/views/global/globalCssVariables.scss | 8 +- .../views/global/globalCssVariables.scss.d.ts | 4 +- 7 files changed, 130 insertions(+), 174 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index 817e45699..4f871f5ec 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -15,8 +15,8 @@ margin-top: 10px; } -.mainContent-div-flyout, -.mainContent-div { +.mainView-dockingContent-flyout, +.mainView-dockingContent { position: relative; width: 100%; height: 100%; @@ -99,7 +99,7 @@ } } -.mainView-mainContent { +.mainView-dashboardArea { width: 100%; height: 100%; position: absolute; @@ -208,7 +208,7 @@ } } -.mainView-menuPanel { +.mainView-leftMenuPanel { min-width: var(--menuPanelWidth); background-color: $dark-gray; border-right: $standard-border; @@ -220,60 +220,6 @@ ::-webkit-scrollbar { width: 0; } - - .mainView-menuPanel-button { - padding: 7px; - padding-left: 7px; - width: 100%; - background: $dark-gray; - - .mainView-menuPanel-button-wrap { - width: 45px; - /* padding: 5px; */ - touch-action: none; - background: $dark-gray; - transform-origin: top left; - /* margin-bottom: 5px; */ - margin-top: 5px; - margin-right: 25px; - border-radius: 8px; - - &:hover { - background: $black; - cursor: pointer; - } - } - } - - .mainView-menuPanel-button-label { - color: white; - margin-left: px; - margin-right: 4px; - border-radius: 8px; - width: 42px; - position: relative; - text-align: center; - font-size: 8px; - margin-top: 1px; - letter-spacing: normal; - padding: 3px; - background-color: inherit; - } - - .mainView-menuPanel-button-icon { - width: auto; - height: 35px; - padding: 5px; - } -} - -.mainView-searchPanel { - width: 100%; - height: $searchpanel-height; - background-color: black; - color: white; - text-align: center; - vertical-align: middle; } .mainView-mainDiv { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index b102c9a1f..5bda9f6bf 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -11,9 +11,10 @@ import * as ReactDOM from 'react-dom'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { List } from '../../fields/List'; import { PrefetchProxy } from '../../fields/Proxy'; +import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, PromiseValue, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; import { Docs, DocUtils } from '../documents/Documents'; @@ -36,11 +37,12 @@ import { CollectionLinearView } from './collections/collectionLinear'; import { CollectionMenu } from './collections/CollectionMenu'; import { CollectionViewType } from './collections/CollectionView'; import "./collections/TreeView.scss"; +import { ComponentDecorations } from './ComponentDecorations'; import { ContextMenu } from './ContextMenu'; import { DictationOverlay } from './DictationOverlay'; import { DocumentDecorations } from './DocumentDecorations'; import { GestureOverlay } from './GestureOverlay'; -import { MENU_PANEL_WIDTH, SEARCH_PANEL_HEIGHT } from './global/globalCssVariables.scss'; +import { DASHBOARD_SELECTOR_HEIGHT, LEFT_MENU_WIDTH } from './global/globalCssVariables.scss'; import { Colors } from './global/globalEnums'; import { KeyManager } from './GlobalKeyHandler'; import { InkStrokeProperties } from './InkStrokeProperties'; @@ -48,9 +50,11 @@ import { LightboxView } from './LightboxView'; import { LinkMenu } from './linking/LinkMenu'; import "./MainView.scss"; import { AudioBox } from './nodes/AudioBox'; +import { ButtonType } from './nodes/button/FontIconBox'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { DocumentView } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { RichTextMenu } from './nodes/formattedText/RichTextMenu'; import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview } from './nodes/LinkDocPreview'; import { RadialMenu } from './nodes/RadialMenu'; @@ -62,10 +66,6 @@ import { PreviewCursor } from './PreviewCursor'; import { PropertiesView } from './PropertiesView'; import { DashboardStyleProvider, DefaultStyleProvider } from './StyleProvider'; import { TopBar } from './topbar/TopBar'; -import { RichTextMenu } from './nodes/formattedText/RichTextMenu'; -import { ScriptField } from '../../fields/ScriptField'; -import { ButtonType } from './nodes/button/FontIconBox'; -import { ComponentDecorations } from './ComponentDecorations'; const _global = (window /* browser */ || global /* node */) as any; @observer @@ -76,21 +76,32 @@ export class MainView extends React.Component { @observable public LastButton: Opt; @observable private _windowWidth: number = 0; @observable private _windowHeight: number = 0; - @observable private _panelWidth: number = 0; - @observable private _panelHeight: number = 0; + @observable private _dashUIWidth: number = 0; // width of entire main dashboard region including left menu buttons and properties panel (but not including the dashboard selector button row) + @observable private _dashUIHeight: number = 0; // height of entire main dashboard region including top menu buttons @observable private _panelContent: string = "none"; @observable private _sidebarContent: any = this.userDoc?.sidebar; - @observable private _flyoutWidth: number = 0; + @observable private _leftMenuFlyoutWidth: number = 0; - @computed private get topOffset() { return 35 + Number(SEARCH_PANEL_HEIGHT.replace("px", "")); } //TODO remove - @computed private get leftOffset() { return this.menuPanelWidth() - 2; } + @computed private get dashboardTabHeight() { return 27; } // 27 comes form lm.config.defaultConfig.dimensions.headerHeight in goldenlayout.js + @computed private get topOfDashUI() { return Number(DASHBOARD_SELECTOR_HEIGHT.replace("px", "")); } + @computed private get topOfMainDoc() { return this.topOfDashUI + this.topMenuHeight(); } + @computed private get topOfMainDocContent() { return this.topOfMainDoc + this.dashboardTabHeight; } + @computed private get leftScreenOffsetOfMainDocView() { return this.leftMenuWidth() - 2; } @computed private get userDoc() { return Doc.UserDoc(); } @computed private get darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkScheme); } @computed private get mainContainer() { return this.userDoc ? CurrentUserUtils.ActiveDashboard : CurrentUserUtils.GuestDashboard; } - @computed public get mainFreeform(): Opt { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); } - - menuPanelWidth = () => Number(MENU_PANEL_WIDTH.replace("px", "")); - propertiesWidth = () => Math.max(0, Math.min(this._panelWidth - 50, CurrentUserUtils.propertiesWidth || 0)); + @computed public get mainFreeform(): Opt { return (docs => (docs?.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); } + + topMenuHeight = () => 35; + topMenuWidth = returnZero; // value is ignored ... + leftMenuWidth = () => Number(LEFT_MENU_WIDTH.replace("px", "")); + leftMenuHeight = () => this._dashUIHeight; + leftMenuFlyoutWidth = () => this._leftMenuFlyoutWidth; + leftMenuFlyoutHeight = () => this._dashUIHeight; + propertiesWidth = () => Math.max(0, Math.min(this._dashUIWidth - 50, CurrentUserUtils.propertiesWidth || 0)); + propertiesHeight = () => this._dashUIHeight; + mainDocViewWidth = () => this._dashUIWidth - this.propertiesWidth() - this.leftMenuWidth(); + mainDocViewHeight = () => this._dashUIHeight - this.topMenuHeight(); componentDidMount() { document.getElementById("root")?.addEventListener("scroll", e => ((ele) => ele.scrollLeft = ele.scrollTop = 0)(document.getElementById("root")!)); @@ -264,11 +275,6 @@ export class MainView extends React.Component { Doc.AddDocToList(this.userDoc.myFilesystem as Doc, "data", folder); } - getPWidth = () => this._panelWidth - this.propertiesWidth(); - getPHeight = () => this._panelHeight - (CollectionMenu.Instance?.Pinned ? 35 : 0); - getContentsHeight = () => this._panelHeight; - getMenuPanelHeight = () => this._panelHeight + (CollectionMenu.Instance?.Pinned ? 35 : 0); - @computed get mainDocView() { return { e.stopPropagation(); e.preventDefault(); }} - // style={{ minWidth: `calc(100% - ${this._flyoutWidth + this.menuPanelWidth() + this.propertiesWidth()}px)`, width: `calc(100% - ${this._flyoutWidth + this.propertiesWidth()}px)` }}> - // FIXME update with property panel width + return
{ e.stopPropagation(); e.preventDefault(); }} style={{ - minWidth: `calc(100% - ${this._flyoutWidth + this.menuPanelWidth() + this.propertiesWidth()}px)`, + minWidth: `calc(100% - ${this._leftMenuFlyoutWidth + this.leftMenuWidth() + this.propertiesWidth()}px)`, transform: LightboxView.LightboxDoc ? "scale(0.0001)" : undefined, }}> {!this.mainContainer ? (null) : this.mainDocView} @@ -312,22 +316,21 @@ export class MainView extends React.Component { @action onPropertiesPointerDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, - action(e => (CurrentUserUtils.propertiesWidth = Math.max(0, this._panelWidth - e.clientX)) ? false : false), + action(e => (CurrentUserUtils.propertiesWidth = Math.max(0, this._dashUIWidth - e.clientX)) ? false : false), action(() => CurrentUserUtils.propertiesWidth < 5 && (CurrentUserUtils.propertiesWidth = 0)), - action(() => CurrentUserUtils.propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._panelWidth - 50, 250) : 0), false); + action(() => CurrentUserUtils.propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._dashUIWidth - 50, 250) : 0), false); } @action onFlyoutPointerDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, - action(e => (this._flyoutWidth = Math.max(e.clientX - 58, 0)) ? false : false), - () => this._flyoutWidth < 5 && this.closeFlyout(), + action(e => (this._leftMenuFlyoutWidth = Math.max(e.clientX - 58, 0)) ? false : false), + () => this._leftMenuFlyoutWidth < 5 && this.closeFlyout(), this.closeFlyout); } - flyoutWidthFunc = () => this._flyoutWidth; - sidebarScreenToLocal = () => new Transform(0, -this.topOffset, 1); - mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftOffset, 0); + sidebarScreenToLocal = () => new Transform(0, -this.topOfMainDoc, 1); + mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftScreenOffsetOfMainDocView, 0); addDocTabFunc = (doc: Doc, where: string): boolean => { return where === "close" ? CollectionDockingView.CloseSplit(doc) : doc.dockingConfig ? CurrentUserUtils.openDashboard(Doc.UserDoc(), doc) : CollectionDockingView.AddSplit(doc, "right"); @@ -335,10 +338,10 @@ export class MainView extends React.Component { @computed get flyout() { - return !this._flyoutWidth ?
+ return !this._leftMenuFlyoutWidth ?
{this.docButtons}
: -
+
; } - @computed get menuPanel() { - return
+ @computed get leftMenuPanel() { + return
{ const title = StrCast(Doc.GetProto(button).title); - const willOpen = !this._flyoutWidth || this._panelContent !== title; + const willOpen = !this._leftMenuFlyoutWidth || this._panelContent !== title; this.closeFlyout(); if (willOpen) { switch (this._panelContent = title) { @@ -422,38 +425,41 @@ export class MainView extends React.Component { } @computed get mainInnerContent() { - const width = this.propertiesWidth() + this._flyoutWidth + this.menuPanelWidth(); - const transform = this._flyoutWidth ? 'translate(-28px, 0px)' : undefined; + const width = this.propertiesWidth() + this._leftMenuFlyoutWidth + this.leftMenuWidth(); + const transform = this._leftMenuFlyoutWidth ? 'translate(-28px, 0px)' : undefined; return <> - {this.menuPanel} + {this.leftMenuPanel}
{this.flyout} -
+
- + {this.dockingContent} -
+
- {this.propertiesWidth() < 10 ? (null) : } + {this.propertiesWidth() < 10 ? (null) : }
; } - @computed get mainContent() { + @computed get mainDashboardArea() { return !this.userDoc ? (null) : -
{ - r && new _global.ResizeObserver(action(() => { this._panelWidth = r.getBoundingClientRect().width; this._panelHeight = r.getBoundingClientRect().height; })).observe(r); +
{ + r && new _global.ResizeObserver(action(() => { + this._dashUIWidth = r.getBoundingClientRect().width; + this._dashUIHeight = r.getBoundingClientRect().height; + })).observe(r); }} style={{ color: this.darkScheme ? "rgb(205,205,205)" : "black", - height: `calc(100% - ${this.topOffset - 35}px)`, + height: `calc(100% - ${this.topOfDashUI}px)`, width: "100%", }} > {this.mainInnerContent} @@ -461,7 +467,7 @@ export class MainView extends React.Component { } expandFlyout = action((button: Doc) => { - this._flyoutWidth = (this._flyoutWidth || 250); + this._leftMenuFlyoutWidth = (this._leftMenuFlyoutWidth || 250); this._sidebarContent.proto = button.target as any; this.LastButton = button; console.log(button.title); @@ -471,7 +477,7 @@ export class MainView extends React.Component { this.LastButton = undefined; this._panelContent = "none"; this._sidebarContent.proto = undefined; - this._flyoutWidth = 0; + this._leftMenuFlyoutWidth = 0; }); remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); @@ -509,8 +515,8 @@ export class MainView extends React.Component { pinToPres={emptyFunction} removeDocument={this.remButtonDoc} ScreenToLocalTransform={this.buttonBarXf} - PanelWidth={this.flyoutWidthFunc} - PanelHeight={this.getContentsHeight} + PanelWidth={this.leftMenuFlyoutWidth} + PanelHeight={this.leftMenuFlyoutHeight} renderDepth={0} focus={DocUtils.DefaultFocus} whenChildContentsActiveChanged={emptyFunction} @@ -606,14 +612,14 @@ export class MainView extends React.Component { - - {/* 27 comes form lm.config.defaultConfig.dimensions.headerHeight in goldenlayout.js */} + + {this.topbar} {LinkDescriptionPopup.descriptionPopup ? : null} {DocumentLinksButton.LinkEditorDocView ? : (null)} {LinkDocPreview.LinkInfo ? : (null)} - {this.mainContent} + {this.mainDashboardArea} diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 6ffa6c279..8e03b2db2 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -42,8 +42,13 @@ import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView"; import { TabDocView } from "./TabDocView"; import { Colors } from "../global/globalEnums"; +interface CollectionMenuProps { + panelHeight: () => number; + panelWidth: () => number; +} + @observer -export class CollectionMenu extends AntimodeMenu { +export class CollectionMenu extends AntimodeMenu{ @observable static Instance: CollectionMenu; @observable SelectedCollection: DocumentView | undefined; @@ -93,13 +98,10 @@ export class CollectionMenu extends AntimodeMenu { return new Transform(-translateX, -translateY, 1 / scale); } - panelWidth100 = () => 100; - panelHeight35 = () => 35; - @computed get contMenuButtons() { trace(); const selDoc = Doc.UserDoc().contextMenuBtns; - return !(selDoc instanceof Doc) ? (null) :
+ return !(selDoc instanceof Doc) ? (null) :
{ pinToPres={emptyFunction} removeDocument={returnFalse} ScreenToLocalTransform={this.buttonBarXf} - PanelWidth={this.panelWidth100} - PanelHeight={this.panelHeight35} + PanelWidth={this.props.panelWidth} + PanelHeight={this.props.panelHeight} renderDepth={0} focus={emptyFunction} whenChildContentsActiveChanged={emptyFunction} @@ -176,7 +178,7 @@ export class CollectionMenu extends AntimodeMenu { } } -interface CollectionMenuProps { +interface CollectionViewMenuProps { type: CollectionViewType; fieldKey: string; docView: DocumentView; @@ -185,7 +187,7 @@ interface CollectionMenuProps { const stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation(); @observer -export class CollectionViewBaseChrome extends React.Component { +export class CollectionViewBaseChrome extends React.Component { //(!)?\(\(\(doc.(\w+) && \(doc.\w+ as \w+\).includes\(\"(\w+)\"\) get document() { return this.props.docView?.props.Document; } @@ -628,14 +630,14 @@ export class CollectionViewBaseChrome extends React.Component { +export class CollectionDockingChrome extends React.Component { render() { return (null); } } @observer -export class CollectionFreeFormViewChrome extends React.Component { +export class CollectionFreeFormViewChrome extends React.Component { public static Instance: CollectionFreeFormViewChrome; constructor(props: any) { super(props); @@ -866,7 +868,7 @@ export class CollectionFreeFormViewChrome extends React.Component { +export class CollectionStackingViewChrome extends React.Component { @observable private _currentKey: string = ""; @observable private suggestions: string[] = []; @@ -987,7 +989,7 @@ export class CollectionStackingViewChrome extends React.Component { +export class CollectionSchemaViewChrome extends React.Component { // private _textwrapAllRows: boolean = Cast(this.document.textwrappedSchemaRows, listSpec("string"), []).length > 0; get document() { return this.props.docView.props.Document; } @@ -1035,7 +1037,7 @@ export class CollectionSchemaViewChrome extends React.Component { +export class CollectionTreeViewChrome extends React.Component { get document() { return this.props.docView.props.Document; } get sortAscending() { @@ -1072,7 +1074,7 @@ export class CollectionTreeViewChrome extends React.Component { +export class Collection3DCarouselViewChrome extends React.Component { get document() { return this.props.docView.props.Document; } @computed get scrollSpeed() { return this.document._autoScrollSpeed; @@ -1113,7 +1115,7 @@ export class Collection3DCarouselViewChrome extends React.Component { +export class CollectionGridViewChrome extends React.Component { private clicked: boolean = false; private entered: boolean = false; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 4d62a1af4..624a0bf4a 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -267,16 +267,17 @@ export class CollectionTreeView extends CollectionSubView 35; @computed get buttonMenu() { - const menuDoc:Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null); + const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null); // To create a multibutton menu add a CollectionLinearView - if (menuDoc){ - + if (menuDoc) { + const width: number = NumCast(menuDoc._width, 30); const height: number = NumCast(menuDoc._height, 30); console.log(menuDoc.title, width, height); return (
+ style={{ width: width, height: height }}> 35} - PanelHeight={() => 35} + PanelWidth={this.return35} + PanelHeight={this.return35} renderDepth={this.props.renderDepth + 1} focus={emptyFunction} styleProvider={this.props.styleProvider} @@ -302,13 +303,14 @@ export class CollectionTreeView extends CollectionSubView
); } } - + @observable _explainerHeight: number = 0; + @computed get nativeWidth() { return Doc.NativeWidth(this.Document, undefined, true); } @computed get nativeHeight() { return Doc.NativeHeight(this.Document, undefined, true); } @@ -336,30 +338,30 @@ export class CollectionTreeView extends CollectionSubView - {this.titleBar} -
- {buttonMenu || noviceExplainer ?
- {buttonMenu ? this.buttonMenu : null} - {Doc.UserDoc().noviceMode && noviceExplainer ? -
- {noviceExplainer} -
- : null - } -
: null} -
e.stopPropagation()} - onDrop={this.onTreeDrop} - ref={this.createTreeDropTarget}> -
    - {this.treeViewElements} -
-
-
- ; + <> + {this.titleBar} +
+ {buttonMenu || noviceExplainer ?
r && (this._explainerHeight = r.getBoundingClientRect().height))}> + {buttonMenu ? this.buttonMenu : null} + {Doc.UserDoc().noviceMode && noviceExplainer ? +
+ {noviceExplainer} +
+ : null + } +
: null} +
e.stopPropagation()} + onDrop={this.onTreeDrop} + ref={this.createTreeDropTarget}> +
    + {this.treeViewElements} +
+
+
+ ; } } \ No newline at end of file diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index aa7b164b0..4fc25752f 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -869,7 +869,7 @@ export class TreeView extends React.Component { const childLayout = Doc.Layout(pair.layout); const rowHeight = () => { const aspect = Doc.NativeAspect(childLayout); - return aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym](); + return (aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym]()); }; return treeViewRefs.set(child, r ? r : undefined)} document={pair.layout} diff --git a/src/client/views/global/globalCssVariables.scss b/src/client/views/global/globalCssVariables.scss index caa9f4fe5..95bd44c1f 100644 --- a/src/client/views/global/globalCssVariables.scss +++ b/src/client/views/global/globalCssVariables.scss @@ -54,7 +54,7 @@ $standard-border-radius: 3px; $standard-box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3); -$searchpanel-height: 32px; +$dashboardselector-height: 32px; $mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc $docDecorations-zindex: 998; // then doc decorations appear over everything else $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? @@ -63,7 +63,7 @@ $SCHEMA_DIVIDER_WIDTH: 4; $MINIMIZED_ICON_SIZE: 24; $MAX_ROW_HEIGHT: 44px; $DFLT_IMAGE_NATIVE_DIM: 900px; -$MENU_PANEL_WIDTH: 60px; +$LEFT_MENU_WIDTH: 60px; $TREE_BULLET_WIDTH: 20px; :export { @@ -74,8 +74,8 @@ $TREE_BULLET_WIDTH: 20px; MAX_ROW_HEIGHT: $MAX_ROW_HEIGHT; SEARCH_THUMBNAIL_SIZE: $search-thumnail-size; ANTIMODEMENU_HEIGHT: $antimodemenu-height; - SEARCH_PANEL_HEIGHT: $searchpanel-height; + DASHBOARD_SELECTOR_HEIGHT: $dashboardselector-height; DFLT_IMAGE_NATIVE_DIM: $DFLT_IMAGE_NATIVE_DIM; - MENU_PANEL_WIDTH: $MENU_PANEL_WIDTH; + LEFT_MENU_WIDTH: $LEFT_MENU_WIDTH; TREE_BULLET_WIDTH: $TREE_BULLET_WIDTH; } \ No newline at end of file diff --git a/src/client/views/global/globalCssVariables.scss.d.ts b/src/client/views/global/globalCssVariables.scss.d.ts index 11e62e1eb..59c2b3585 100644 --- a/src/client/views/global/globalCssVariables.scss.d.ts +++ b/src/client/views/global/globalCssVariables.scss.d.ts @@ -7,9 +7,9 @@ interface IGlobalScss { MAX_ROW_HEIGHT: string; SEARCH_THUMBNAIL_SIZE: string; ANTIMODEMENU_HEIGHT: string; - SEARCH_PANEL_HEIGHT: string; + DASHBOARD_SELECTOR_HEIGHT: string; DFLT_IMAGE_NATIVE_DIM: string; - MENU_PANEL_WIDTH: string; + LEFT_MENU_WIDTH: string; TREE_BULLET_WIDTH: string; } declare const globalCssVariables: IGlobalScss; -- cgit v1.2.3-70-g09d2 From 4b2f4d191e5091b82e67c2bd6c0f54b1898153e9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 22:52:22 -0400 Subject: fixed create new folder in file system --- src/client/util/CurrentUserUtils.ts | 14 ++++++++++++-- src/client/views/EditableView.tsx | 1 - src/client/views/collections/CollectionStackingView.tsx | 1 - 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 6a7523d5b..d5dc9e2be 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -38,6 +38,7 @@ import { ColorScheme } from "./SettingsManager"; import { SharingManager } from "./SharingManager"; import { SnappingManager } from "./SnappingManager"; import { UndoManager } from "./UndoManager"; +import { TreeView } from "../views/collections/TreeView"; interface Button { title?: string; @@ -853,8 +854,12 @@ export class CurrentUserUtils { if (doc.myFilesystem === undefined) { doc.myFileOrphans = Docs.Create.TreeDocument([], { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true }); // doc.myFileRoot = Docs.Create.TreeDocument([], { title: "file root", _stayInCollection: true, system: true, isFolder: true }); - const newFolder = ScriptField.MakeFunction(`doc.makeFolder()`, { doc: doc.myFilesystem })!; - const newFolderButton: Doc = Docs.Create.FontIconDocument({ onClick: newFolder, _forceActive: true, toolTip: "Create new folder", _stayInCollection: true, _hideContextMenu: true, title: "New folder", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New folder", icon: "folder-plus", system: true }); + const newFolder = ScriptField.MakeFunction(`makeTopLevelFolder()`, { scriptContext: "any" })!; + const newFolderButton: Doc = Docs.Create.FontIconDocument({ + onClick: newFolder, _forceActive: true, toolTip: "Create new folder", + _stayInCollection: true, _hideContextMenu: true, title: "New folder", btnType: ButtonType.ClickButton, _width: 30, _height: 30, + buttonText: "New folder", icon: "folder-plus", system: true + }); doc.myFilesystem = new PrefetchProxy(Docs.Create.TreeDocument([doc.myFileOrphans as Doc], { title: "My Documents", _showTitle: "title", buttonMenu: true, buttonMenuDoc: newFolderButton, _height: 100, treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", @@ -1628,3 +1633,8 @@ Scripting.addGlobal(function selectedDocumentType(docType?: DocumentType, colTyp else if (selected && !colType && !docType) return false; else return true; }); +Scripting.addGlobal(function makeTopLevelFolder() { + const folder = Docs.Create.TreeDocument([], { title: "Untitled folder", _stayInCollection: true, isFolder: true }); + TreeView._editTitleOnLoad = { id: folder[Id], parent: undefined }; + return Doc.AddDocToList(Doc.UserDoc().myFilesystem as Doc, "data", folder); +}); \ No newline at end of file diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index ebf5ca82d..d7707a6fe 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -158,7 +158,6 @@ export class EditableView extends React.Component { renderEditor() { - console.log("render editor", this.props.autosuggestProps); return this.props.autosuggestProps ? {buttonMenu || noviceExplainer ?
-- cgit v1.2.3-70-g09d2 From 72e6023a199fc859cc84c5d22bb12e948d4a471b Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 23:10:06 -0400 Subject: added a deleteFolder option for empty folders in the filesystem --- src/client/views/collections/TreeView.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 4fc25752f..6bb7fb748 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -244,6 +244,9 @@ export class TreeView extends React.Component { TreeView._editTitleOnLoad = { id: folder[Id], parent: this.props.parentTreeView }; return this.props.addDocument(folder); } + deleteFolder = () => { + return this.props.removeDoc?.(this.doc); + } preTreeDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => { const dragData = de.complete.docDragData; @@ -513,9 +516,11 @@ export class TreeView extends React.Component { } contextMenuItems = () => { const makeFolder = { script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: "any" })!, icon: "folder-plus", label: "New Folder" }; + const deleteFolder = { script: ScriptField.MakeFunction(`scriptContext.deleteFolder()`, { scriptContext: "any" })!, icon: "folder-plus", label: "Delete Folder" }; + const folderOp = this.childDocs?.length ? makeFolder : deleteFolder; const openAlias = { script: ScriptField.MakeFunction(`openOnRight(getAlias(self))`)!, icon: "copy", label: "Open Alias" }; const focusDoc = { script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, icon: "eye", label: "Focus or Open" }; - return [...this.props.contextMenuItems.filter(mi => !mi.filter ? true : mi.filter.script.run({ doc: this.doc })?.result), ... (this.doc.isFolder ? [makeFolder] : + return [...this.props.contextMenuItems.filter(mi => !mi.filter ? true : mi.filter.script.run({ doc: this.doc })?.result), ... (this.doc.isFolder ? [folderOp] : Doc.IsSystem(this.doc) ? [] : this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc) ? [openAlias, makeFolder] : -- cgit v1.2.3-70-g09d2 From e1533161b473f31544d018432abc8a9c8d4d0bfc Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 14 Sep 2021 23:16:17 -0400 Subject: fixed treeviews so that in filesys mode you can't indent a document into anything other than a folder. --- src/client/views/collections/TreeView.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 6bb7fb748..97de097e0 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -858,6 +858,7 @@ export class TreeView extends React.Component { } const dentDoc = (editTitle: boolean, newParent: Doc, addAfter: Doc | undefined, parent: TreeView | CollectionTreeView | undefined) => { + if (parent instanceof TreeView && parent.props.treeView.fileSysMode && !newParent.isFolder) return; const fieldKey = Doc.LayoutFieldKey(newParent); if (remove && fieldKey && Cast(newParent[fieldKey], listSpec(Doc)) !== undefined) { remove(child); -- cgit v1.2.3-70-g09d2 From 1ca0db9a94e8f1141f8f52446afb53e29cff0e01 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 09:30:15 -0400 Subject: fixed dragging document in filesystem to not create duplicates in some cases --- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/collections/CollectionTreeView.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 06d20f015..cb8b55cb2 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -216,7 +216,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: const targetDocments = DocListCast(this.dataDoc[this.props.fieldKey]); const someMoved = !docDragData.userDropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag)); if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop); - if ((!dropAction || dropAction === "move" || someMoved) && docDragData.moveDocument) { + if ((!dropAction || dropAction === "same" || dropAction === "move" || someMoved) && docDragData.moveDocument) { const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); if (movedDocs.length) { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 624a0bf4a..3852987b9 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -108,7 +108,7 @@ export class CollectionTreeView extends CollectionSubView { const dragData = de.complete.docDragData; if (dragData) { - const isInTree = () => dragData.draggedDocuments.some(d => d.context === this.doc && this.childDocs.includes(d)); + const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.context === this.doc && this.childDocs.includes(d)); dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? "same" : dragData.dropAction; } } -- cgit v1.2.3-70-g09d2 From a6c7dc12a4a6b2c51c0363876e892a1adb0b382a Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 10:02:55 -0400 Subject: fixed dragging so that only isDocumentActive documents are dragged (get move events) which fixes a bug where a nested document and its container might both be dragged at the same time. --- src/client/util/DragManager.ts | 4 ++-- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 12 ++++++------ src/client/views/nodes/formattedText/FormattedTextBox.tsx | 8 +++++--- 4 files changed, 14 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index f7ef9ae6f..421e4c6bb 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -145,7 +145,7 @@ export namespace DragManager { removeDropProperties?: string[]; moveDocument?: MoveFunction; removeDocument?: RemoveFunction; - isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged. this will suppress onDragStart scripts + isDocDecorationMove?: boolean; // Flags that Document decorations are used to drag document which allows suppression of onDragStart scripts } export class LinkDragData { constructor(dragView: DocumentView, linkSourceGetAnchor: () => Doc,) { @@ -225,7 +225,7 @@ export namespace DragManager { if (docDragData && !docDragData.droppedDocuments.length) { docDragData.dropAction = dragData.userDropAction || dragData.dropAction; docDragData.droppedDocuments = - await Promise.all(dragData.draggedDocuments.map(async d => !dragData.isSelectionMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) : + await Promise.all(dragData.draggedDocuments.map(async d => !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) : docDragData.dropAction === "alias" ? Doc.MakeAlias(d) : docDragData.dropAction === "proto" ? Doc.GetProto(d) : docDragData.dropAction === "copy" ? (await Doc.MakeClone(d)).clone : d)); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 5ffdb8ea1..e70ce4664 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -122,7 +122,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P const dragData = new DragManager.DocumentDragData(SelectionManager.Views().map(dv => dv.props.Document), dragDocView.props.dropAction); dragData.offset = dragDocView.props.ScreenToLocalTransform().transformDirection(e.x - left, e.y - top); dragData.moveDocument = dragDocView.props.moveDocument; - dragData.isSelectionMove = true; + dragData.isDocDecorationMove = true; dragData.canEmbed = dragTitle; this._hidden = this.Interacting = true; DragManager.StartDocumentDrag(SelectionManager.Views().map(dv => dv.ContentDiv!), dragData, e.x, e.y, { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b680fcf3b..e8a78d75c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -529,9 +529,11 @@ export class DocumentViewInternal extends DocComponent { if (e.cancelBubble) return; if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) return; - if (e.cancelBubble && this.props.isDocumentActive?.()) { - document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView) - } - else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { + + 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) { if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index acc2892d8..caca215e5 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -435,10 +435,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp view.dispatch(view.state.tr.removeMark(start, end, nmark).addMark(start, end, nmark)); } protected createDropTarget = (ele: HTMLDivElement) => { - this.ProseRef = ele; - this.setupEditor(this.config, this.props.fieldKey); this._dropDisposer?.(); - ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc)); + this.ProseRef = ele; + if (ele) { + this.setupEditor(this.config, this.props.fieldKey); + this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc); + } // if (this.autoHeight) this.tryUpdateScrollHeight(); } -- cgit v1.2.3-70-g09d2 From f71b10a04506cd45ec157a05dbe41217380d814f Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 12:14:49 -0400 Subject: fixed documentdecoration resizers. fixed grouping and added button to switch between freeform / group --- src/client/views/DocumentDecorations.scss | 23 +--------------------- src/client/views/PropertiesButtons.tsx | 11 +++++++++++ src/client/views/collections/CollectionMenu.tsx | 1 - src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 19 ++++++++++++++---- .../views/nodes/formattedText/RichTextMenu.tsx | 1 - 6 files changed, 28 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 76b7481a0..a9f50f81b 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -7,27 +7,7 @@ $linkGap: 3px; z-index: 2000; } .documentDecorations-container { - z-index: $docDecorations-zindex; - position: absolute; - top: 0; - left: 0; - display: grid; - grid-template-rows: 20px 8px 1fr 8px; - grid-template-columns: 8px 16px 1fr 8px 8px; - pointer-events: none; - - .documentDecorations-centerCont { - grid-column: 3; - background: none; - } - - .documentDecorations-selectorButton { - pointer-events: auto; - height: 15px; - width: 15px; - left: -20px; - top: 20px; - display: inline-block; + z-index: $docDecorations-zindex; position: absolute; top: 0; left: 0; @@ -142,7 +122,6 @@ $linkGap: 3px; .documentDecorations-bottomRightResizer:hover { opacity: 1; } - } .documentDecorations-topLeftResizer, .documentDecorations-leftResizer, diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index dd737dc9d..e3da7ce2a 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -16,6 +16,8 @@ import { DocumentView } from './nodes/DocumentView'; import './PropertiesButtons.scss'; import React = require("react"); import { Colors } from "./global/globalEnums"; +import { CollectionFreeFormView } from "./collections/collectionFreeForm"; +import { DocumentManager } from "../util/DocumentManager"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -86,6 +88,14 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get gridButton() { return this.propertyToggleBtn("Grid", "_backgroundGridShow", on => `Display background grid in collection`, on => "border-all"); } + @computed get groupButton() { + return this.propertyToggleBtn("Group", "isGroup", on => `Display collection as a Group`, on => "object-group", (dv, doc) => { + doc.isGroup = !doc.isGroup; + doc.forceActive = doc.isGroup; + const dview = dv || DocumentManager.Instance.getFirstDocumentView(doc); + (dview?.ComponentView as CollectionFreeFormView)?.updateGroupBounds?.() + }); + } @computed get snapButton() { return this.propertyToggleBtn("Snap\xA0Lines", "showSnapLines", on => `Display snapping lines when objects are dragged`, on => "border-all", undefined, true); } @@ -219,6 +229,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { {toggle(this.maskButton, { display: !isInk ? "none" : "" })} {toggle(this.chromeButton, { display: !isCollection || isNovice ? "none" : "" })} {toggle(this.gridButton, { display: !isCollection ? "none" : "" })} + {toggle(this.groupButton, { display: !isCollection ? "none" : "" })} {toggle(this.snapButton, { display: !isCollection ? "none" : "" })} {toggle(this.clustersButton, { display: !isFreeForm ? "none" : "" })} {toggle(this.panButton, { display: !isFreeForm ? "none" : "" })} diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 8e03b2db2..2c2d5dc75 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -99,7 +99,6 @@ export class CollectionMenu extends AntimodeMenu{ } @computed get contMenuButtons() { - trace(); const selDoc = Doc.UserDoc().contextMenuBtns; return !(selDoc instanceof Doc) ? (null) :
func(CollectionViewType.Map), icon: "globe-americas" }); subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" }); - if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.annotationOn) { + if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) { const existingVm = ContextMenu.Instance.findByDescription(category); const catItems = existingVm && "subitems" in existingVm ? existingVm.subitems : []; catItems.push({ description: "Add a Perspective...", addDivider: true, noexpand: true, subitems: subItems, icon: "eye" }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c8561d901..ef127d328 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -183,7 +183,7 @@ export class CollectionFreeFormView extends CollectionSubView { let retVal = false; if (newBox instanceof Doc) { - if (retVal = this.props.addDocument?.(newBox) || false) { + if (retVal = (this.props.addDocument?.(newBox) || false)) { this.bringToFront(newBox); this.updateCluster(newBox); } @@ -1236,6 +1236,7 @@ export class CollectionFreeFormView extends CollectionSubView Doc.Zip(this.props.Document) }); - moreItems.push({ description: "Import exported collection", icon: "upload", event: ({ x, y }) => this.importDocument(x, y) }); + if (!Doc.UserDoc().noviceMode) { + moreItems.push({ description: "Export collection", icon: "download", event: async () => Doc.Zip(this.props.Document) }); + moreItems.push({ description: "Import exported collection", icon: "upload", event: ({ x, y }) => this.importDocument(x, y) }); + } !mores && ContextMenu.Instance.addItem({ description: "More...", subitems: moreItems, icon: "eye" }); } @@ -1484,6 +1487,14 @@ export class CollectionFreeFormView extends CollectionSubView { //used for stacking and masonry view + this.groupDropDisposer?.(); + if (ele) { + this.groupDropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc, this.onInternalPreDrop.bind(this)); + } + } + render() { TraceMobx(); const clientRect = this._mainCont?.getBoundingClientRect(); @@ -1527,7 +1538,7 @@ export class CollectionFreeFormView extends CollectionSubView} {this.props.Document._isGroup && SnappingManager.GetIsDragging() && (this.ChildDrag || this.props.layerProvider?.(this.props.Document) === false) ? -
{ const path = (this.view.state.selection.$from as any).path; for (let i = path.length - 3; i < path.length && i >= 0; i -= 3) { if (path[i]?.type === this.view.state.schema.nodes.paragraph || path[i]?.type === this.view.state.schema.nodes.heading) { - console.log(path[i].attrs); return path[i].attrs.strong; } } -- cgit v1.2.3-70-g09d2 From ed1897d66ef9c982dabc4b4fc4b05d0fb072a127 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 12:30:53 -0400 Subject: prevent groups from being opened in lightbox because its odd and there are bugs. prevent tabViews from being switchable into a group because its odd. --- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/PropertiesButtons.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index e70ce4664..6f9697703 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -420,7 +420,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P if (SnappingManager.GetIsDragging() || bounds.r - bounds.x < 1 || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) { return (null); } - const canOpen = SelectionManager.Views().some(docView => !docView.props.Document._stayInCollection); + const canOpen = SelectionManager.Views().some(docView => !docView.props.Document._stayInCollection && !docView.props.Document.isGroup); const canDelete = SelectionManager.Views().some(docView => { const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit; return (!docView.rootDoc._stayInCollection || docView.rootDoc.isInkMask) && diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index e3da7ce2a..e3de80009 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -32,6 +32,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { @observable public static Instance: PropertiesButtons; @computed get selectedDoc() { return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.rootDoc; } + @computed get selectedTabView() { return !SelectionManager.SelectedSchemaDoc() && SelectionManager.Views().lastElement()?.topMost; } propertyToggleBtn = (label: string, property: string, tooltip: (on?: any) => string, icon: (on: boolean) => string, onClick?: (dv: Opt, doc: Doc, property: string) => void, useUserDoc?: boolean) => { const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedDoc; @@ -214,6 +215,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { const isStacking = this.selectedDoc?._viewType === CollectionViewType.Stacking; const isFreeForm = this.selectedDoc?._viewType === CollectionViewType.Freeform; const isTree = this.selectedDoc?._viewType === CollectionViewType.Tree; + const isTabView = this.selectedTabView; const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) =>
{ele}
; const isNovice = Doc.UserDoc().noviceMode; return !this.selectedDoc ? (null) : @@ -229,7 +231,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { {toggle(this.maskButton, { display: !isInk ? "none" : "" })} {toggle(this.chromeButton, { display: !isCollection || isNovice ? "none" : "" })} {toggle(this.gridButton, { display: !isCollection ? "none" : "" })} - {toggle(this.groupButton, { display: !isCollection ? "none" : "" })} + {toggle(this.groupButton, { display: isTabView || !isCollection ? "none" : "" })} {toggle(this.snapButton, { display: !isCollection ? "none" : "" })} {toggle(this.clustersButton, { display: !isFreeForm ? "none" : "" })} {toggle(this.panButton, { display: !isFreeForm ? "none" : "" })} -- cgit v1.2.3-70-g09d2 From c351117e33c050d237ec2d0d68ec3b078fecc4f7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 12:42:41 -0400 Subject: cleaned up recomputing group bounds to use a reaction --- src/client/views/PropertiesButtons.tsx | 7 +----- .../collectionFreeForm/CollectionFreeFormView.tsx | 28 +++++++++++++++++++--- 2 files changed, 26 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index e3de80009..378c67253 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -90,12 +90,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { return this.propertyToggleBtn("Grid", "_backgroundGridShow", on => `Display background grid in collection`, on => "border-all"); } @computed get groupButton() { - return this.propertyToggleBtn("Group", "isGroup", on => `Display collection as a Group`, on => "object-group", (dv, doc) => { - doc.isGroup = !doc.isGroup; - doc.forceActive = doc.isGroup; - const dview = dv || DocumentManager.Instance.getFirstDocumentView(doc); - (dview?.ComponentView as CollectionFreeFormView)?.updateGroupBounds?.() - }); + return this.propertyToggleBtn("Group", "isGroup", on => `Display collection as a Group`, on => "object-group", (dv, doc) => { doc.isGroup = !doc.isGroup; doc.forceActive = doc.isGroup; }); } @computed get snapButton() { return this.propertyToggleBtn("Snap\xA0Lines", "showSnapLines", on => `Display snapping lines when objects are dragged`, on => "border-all", undefined, true); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ef127d328..d73aed07c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -212,7 +212,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (!this.props.Document._isGroup) return; const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); - const cbounds = aggregateBounds(clist, 0, 0); + const cbounds = aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; const pbounds = { @@ -269,7 +269,7 @@ export class CollectionFreeFormView extends CollectionSubView { + if (!this.props.Document._isGroup) return { pbounds: undefined, cbounds: undefined }; + const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); + const cbounds = aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); + const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; + const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; + const pbounds = { + x: (cbounds.x - p[0]) * this.zoomScaling() + c[0], y: (cbounds.y - p[1]) * this.zoomScaling() + c[1], + r: (cbounds.r - p[0]) * this.zoomScaling() + c[0], b: (cbounds.b - p[1]) * this.zoomScaling() + c[1] + }; + return { pbounds, cbounds }; + }, ({ pbounds, cbounds }) => { + if (pbounds && cbounds) { + this.layoutDoc._width = (pbounds.r - pbounds.x); + this.layoutDoc._height = (pbounds.b - pbounds.y); + this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2; + this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2; + this.layoutDoc.x = pbounds.x; + this.layoutDoc.y = pbounds.y; + } + }, { fireImmediately: true }); } componentWillUnmount() { -- cgit v1.2.3-70-g09d2 From 46283667f9c183fffe171d728fa043704d8fab01 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 12:54:33 -0400 Subject: fixed bug from last --- .../collectionFreeForm/CollectionFreeFormView.tsx | 62 ++++++++-------------- 1 file changed, 21 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d73aed07c..8128cb0d9 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -209,25 +209,6 @@ export class CollectionFreeFormView extends CollectionSubView { - if (!this.props.Document._isGroup) return; - const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); - const cbounds = aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); - const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; - const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; - const pbounds = { - x: (cbounds.x - p[0]) * this.zoomScaling() + c[0], y: (cbounds.y - p[1]) * this.zoomScaling() + c[1], - r: (cbounds.r - p[0]) * this.zoomScaling() + c[0], b: (cbounds.b - p[1]) * this.zoomScaling() + c[1] - }; - - this.layoutDoc._width = (pbounds.r - pbounds.x); - this.layoutDoc._height = (pbounds.b - pbounds.y); - this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2; - this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2; - this.layoutDoc.x = pbounds.x; - this.layoutDoc.y = pbounds.y; - } - isCurrent(doc: Doc) { const dispTime = NumCast(doc._timecodeToShow, -1); const endTime = NumCast(doc._timecodeToHide, dispTime + 1.5); @@ -269,8 +250,6 @@ export class CollectionFreeFormView extends CollectionSubView { - if (!this.props.Document._isGroup) return { pbounds: undefined, cbounds: undefined }; - const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); - const cbounds = aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); - const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; - const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; - const pbounds = { - x: (cbounds.x - p[0]) * this.zoomScaling() + c[0], y: (cbounds.y - p[1]) * this.zoomScaling() + c[1], - r: (cbounds.r - p[0]) * this.zoomScaling() + c[0], b: (cbounds.b - p[1]) * this.zoomScaling() + c[1] - }; - return { pbounds, cbounds }; - }, ({ pbounds, cbounds }) => { - if (pbounds && cbounds) { - this.layoutDoc._width = (pbounds.r - pbounds.x); - this.layoutDoc._height = (pbounds.b - pbounds.y); - this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2; - this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2; - this.layoutDoc.x = pbounds.x; - this.layoutDoc.y = pbounds.y; + if (this.props.Document._isGroup) { + const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); + return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); } - }, { fireImmediately: true }); + return undefined; + }, + (cbounds) => { + if (cbounds) { + const c = [NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym]() / 2, NumCast(this.layoutDoc.y) + this.layoutDoc[HeightSym]() / 2]; + const p = [NumCast(this.layoutDoc._panX), NumCast(this.layoutDoc._panY)]; + const pbounds = { + x: (cbounds.x - p[0]) * this.zoomScaling() + c[0], y: (cbounds.y - p[1]) * this.zoomScaling() + c[1], + r: (cbounds.r - p[0]) * this.zoomScaling() + c[0], b: (cbounds.b - p[1]) * this.zoomScaling() + c[1] + }; + this.layoutDoc._width = (pbounds.r - pbounds.x); + this.layoutDoc._height = (pbounds.b - pbounds.y); + this.layoutDoc._panX = (cbounds.r + cbounds.x) / 2; + this.layoutDoc._panY = (cbounds.b + cbounds.y) / 2; + this.layoutDoc.x = pbounds.x; + this.layoutDoc.y = pbounds.y; + } + }); } componentWillUnmount() { -- cgit v1.2.3-70-g09d2 From 2a287df36a6a2acbc5dad4360db6a6840573d364 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 13:05:21 -0400 Subject: fixed infinite loop in grid space selection that conflated with setting group bounds automatically when rendered --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8128cb0d9..cb912484f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1238,7 +1238,7 @@ export class CollectionFreeFormView extends CollectionSubView { + if (!this.zoomScaling()) return 50; const divisions = this.props.PanelWidth() / this.zoomScaling() / gridSpace + 3; return divisions < 60 ? gridSpace : this.chooseGridSpace(gridSpace * 10); } -- cgit v1.2.3-70-g09d2 From afb0c5cb864815fee6ec357defe06813487f337a Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 13:15:50 -0400 Subject: avoid runtime error in compute group bounds on startup when docs are still promises. --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index cb912484f..362839852 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1217,7 +1217,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.Document._isGroup) { + if (this.props.Document._isGroup && this.childDocs.length) { const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); } -- cgit v1.2.3-70-g09d2 From 8386ad690c10d5c76bbd1b4f85314514b7f11b55 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 13:20:26 -0400 Subject: better fix for last that reduces recomputation. --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 362839852..be0b078ec 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1217,7 +1217,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.Document._isGroup && this.childDocs.length) { + if (this.props.Document._isGroup && this.childDocs.length === this.childDocList?.length) { const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: cd[WidthSym](), height: cd[HeightSym]() })); return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding)); } -- cgit v1.2.3-70-g09d2 From c3758877393812d5c25230b486d1b235796fc1bc Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 14:41:24 -0400 Subject: fix earlier breaking changes for showing annotation bar and displaying context menu --- src/client/views/nodes/WebBox.tsx | 44 +++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 19135b6dd..fe5070fa4 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -69,10 +69,8 @@ export class WebBox extends ViewBoxAnnotatableComponent this._scrollHeight; @@ -391,20 +401,22 @@ export class WebBox extends ViewBoxAnnotatableComponent { + specificContextMenu = (e: React.MouseEvent | PointerEvent): void => { const cm = ContextMenu.Instance; const funcs: ContextMenuProps[] = []; - funcs.push({ description: (this.layoutDoc.useCors ? "Don't Use" : "Use") + " Cors", event: () => this.layoutDoc.useCors = !this.layoutDoc.useCors, icon: "snowflake" }); - funcs.push({ - description: (!this.layoutDoc.allowReflow ? "Allow" : "Prevent") + " Reflow", event: () => { - const nw = !this.layoutDoc.allowReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.scaling?.() || 1); - this.layoutDoc.allowReflow = !nw; - if (nw) { - Doc.SetInPlace(this.layoutDoc, this.fieldKey + "-nativeWidth", nw, true); - } - }, icon: "snowflake" - }); - cm.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); + if (!cm.findByDescription("Options...")) { + funcs.push({ description: (this.layoutDoc.useCors ? "Don't Use" : "Use") + " Cors", event: () => this.layoutDoc.useCors = !this.layoutDoc.useCors, icon: "snowflake" }); + funcs.push({ + description: (!this.layoutDoc.allowReflow ? "Allow" : "Prevent") + " Reflow", event: () => { + const nw = !this.layoutDoc.allowReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.scaling?.() || 1); + this.layoutDoc.allowReflow = !nw; + if (nw) { + Doc.SetInPlace(this.layoutDoc, this.fieldKey + "-nativeWidth", nw, true); + } + }, icon: "snowflake" + }); + cm.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); + } } @action -- cgit v1.2.3-70-g09d2 From 1395ce3fbf73bf5df5ed4add744c333cfc8008c9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 15 Sep 2021 15:43:24 -0400 Subject: another windows fix for contextmenus on web pages --- src/client/views/MainView.tsx | 1 + src/client/views/nodes/WebBox.tsx | 30 ++++++++++++++++++------------ 2 files changed, 19 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5bda9f6bf..d854f118f 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -214,6 +214,7 @@ export class MainView extends React.Component { } } }, false); + document.oncontextmenu = () => false; } initAuthenticationRouters = async () => { diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index fe5070fa4..cce71329d 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -224,15 +224,20 @@ export class WebBox extends ViewBoxAnnotatableComponent - {this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => - ) - } -
; + return !this.inlineTextAnnotations.length ? (null) : +
+ {this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => + ) + } +
; } @observable _showSidebar = false; -- cgit v1.2.3-70-g09d2 From 1643bfbbbe25fbd721d19ff2b77e795c6a2609d3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 16 Sep 2021 10:26:12 -0400 Subject: fixed unused code for embedding document references in text --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 5 +++-- src/client/views/nodes/formattedText/RichTextRules.ts | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index caca215e5..3c2ff2df5 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -462,10 +462,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const target = dragData.droppedDocuments[0]; target._fitToBox = true; const node = schema.nodes.dashDoc.create({ - width: target[WidthSym](), height: target[HeightSym](), + width: target[WidthSym](), + height: target[HeightSym](), title: "dashDoc", docid: target[Id], - float: "right" + float: "unset" }); const view = this._editorView!; view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node)); diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 3fd7d61fa..711136469 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -282,7 +282,7 @@ export class RichTextRules { if (rstate) { this.TextBox.EditorView?.dispatch(rstate.tr.setSelection(new TextSelection(rstate.doc.resolve(start), rstate.doc.resolve(end - 3)))); } - const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: rawdocid, _width: 500, _height: 500, }, docid); + const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: rawdocid.replace(/^:/, ""), _width: 500, _height: 500, }, docid); DocUtils.MakeLink({ doc: this.TextBox.getAnchor() }, { doc: target }, "portal to", undefined); const fstate = this.TextBox.EditorView?.state; @@ -290,7 +290,7 @@ export class RichTextRules { this.TextBox.EditorView?.dispatch(fstate.tr.setSelection(new TextSelection(fstate.doc.resolve(selection)))); } }); - return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 2); + return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 3); } return state.tr; } -- cgit v1.2.3-70-g09d2 From 0ad7c7d6abe68ed5c9520c9b671f07013b8d86df Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 16 Sep 2021 17:47:18 -0400 Subject: made embedded dash docs in RTF resize when changed -- but they lose focus --- .../views/nodes/formattedText/DashDocView.tsx | 59 +++++++++++++--------- 1 file changed, 36 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 8915d7c47..e519de1c5 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -1,7 +1,7 @@ import { IReactionDisposer, reaction, observable, action } from "mobx"; import { NodeSelection } from "prosemirror-state"; import { Doc, HeightSym, WidthSym } from "../../../../fields/Doc"; -import { Cast, StrCast } from "../../../../fields/Types"; +import { Cast, StrCast, NumCast } from "../../../../fields/Types"; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, Utils, returnTransparent } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; @@ -69,30 +69,31 @@ export class DashDocViewInternal extends React.Component { @observable _finalLayout: any; @observable _resolvedDataDoc: any; - constructor(props: IDashDocViewInternal) { - super(props); - this._textBox = this.props.tbox; - const updateDoc = action((dashDoc: Doc) => { - this._dashDoc = dashDoc; - this._finalLayout = this.props.docid ? dashDoc : Doc.expandTemplateLayout(Doc.Layout(dashDoc), dashDoc, this.props.fieldKey); + updateDoc = action((dashDoc: Doc) => { + this._dashDoc = dashDoc; + this._finalLayout = this.props.docid ? dashDoc : Doc.expandTemplateLayout(Doc.Layout(dashDoc), dashDoc, this.props.fieldKey); - if (this._finalLayout) { - if (!Doc.AreProtosEqual(this._finalLayout, dashDoc)) { - this._finalLayout.rootDocument = dashDoc.aliasOf; - } - this._resolvedDataDoc = Cast(this._finalLayout.resolvedDataDoc, Doc, null); + if (this._finalLayout) { + if (!Doc.AreProtosEqual(this._finalLayout, dashDoc)) { + this._finalLayout.rootDocument = dashDoc.aliasOf; } - if (this.props.width !== (this._dashDoc?._width ?? "") + "px" || this.props.height !== (this._dashDoc?._height ?? "") + "px") { - try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made - this.props.view.dispatch(this.props.view.state.tr.setNodeMarkup(this.props.getPos(), null, { - ...this.props.node.attrs, width: (this._dashDoc?._width ?? "") + "px", height: (this._dashDoc?._height ?? "") + "px" - })); - } catch (e) { - console.log("DashDocView:" + e); - } + this._resolvedDataDoc = Cast(this._finalLayout.resolvedDataDoc, Doc, null); + } + if (this.props.width !== (this._dashDoc?._width ?? "") + "px" || this.props.height !== (this._dashDoc?._height ?? "") + "px") { + try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made + this.props.view.dispatch(this.props.view.state.tr.setNodeMarkup(this.props.getPos(), null, { + ...this.props.node.attrs, width: (this._dashDoc?._width ?? "") + "px", height: (this._dashDoc?._height ?? "") + "px" + })); + } catch (e) { + console.log("DashDocView:" + e); } - }); + } + }); + + constructor(props: IDashDocViewInternal) { + super(props); + this._textBox = this.props.tbox; DocServer.GetRefField(this.props.docid + this.props.alias).then(async dashDoc => { if (!(dashDoc instanceof Doc)) { @@ -101,15 +102,27 @@ export class DashDocViewInternal extends React.Component { const aliasedDoc = Doc.MakeAlias(dashDocBase, this.props.docid + this.props.alias); aliasedDoc.layoutKey = "layout"; this.props.fieldKey && DocUtils.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, this.props.fieldKey, undefined); - updateDoc(aliasedDoc); + this.updateDoc(aliasedDoc); } }); } else { - updateDoc(dashDoc); + this.updateDoc(dashDoc); } }); } + componentDidMount() { + this._disposers.upater = reaction(() => this._dashDoc && (NumCast(this._dashDoc._height) + NumCast(this._dashDoc._width)), + () => { + if (this._dashDoc) { + this.props.view.dispatch(this.props.view.state.tr.setNodeMarkup(this.props.getPos(), null, { + ...this.props.node.attrs, width: (this._dashDoc?._width ?? "") + "px", height: (this._dashDoc?._height ?? "") + "px" + })); + } + }); + } + + removeDoc = () => { this.props.view.dispatch(this.props.view.state.tr .setSelection(new NodeSelection(this.props.view.state.doc.resolve(this.props.getPos()))) -- cgit v1.2.3-70-g09d2 From 68b20c7cf3b3472a7c7adbdcffa2318ad3549d8d Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 16 Sep 2021 17:47:50 -0400 Subject: webbox search coming soon --- src/client/views/nodes/WebBox.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index cce71329d..0c9c36418 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -623,6 +623,25 @@ export class WebBox extends ViewBoxAnnotatableComponent
+ {/*
+ { + if (e.key === "Enter") { + (this._iframe?.contentWindow as any)?.find(e.target.value); + } + }} onChange={e => { + this._iframe?.contentWindow?.getSelection()?.empty(); + (this._iframe?.contentWindow as any)?.find(e.target.value) + }}> +
*/}
); } } -- cgit v1.2.3-70-g09d2 From 64119b5d8766725025b8b2bfda72f2401bba0f00 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 16 Sep 2021 21:04:57 -0400 Subject: added search() component method. changed search menu to call search on documents that match search string. added seach bar for web pages. --- src/client/views/GlobalKeyHandler.ts | 16 ++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 1 + src/client/views/nodes/PDFBox.tsx | 18 ++++- src/client/views/nodes/WebBox.scss | 86 ++++++++++++++++++++++ src/client/views/nodes/WebBox.tsx | 65 +++++++++++----- src/client/views/pdf/PDFViewer.tsx | 13 +--- src/client/views/search/SearchBox.tsx | 15 ++-- 8 files changed, 172 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index f66c9c788..de6f4ae8b 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -10,10 +10,11 @@ import { Cast, PromiseValue } from "../../fields/Types"; import { GoogleAuthenticationManager } from "../apis/GoogleAuthenticationManager"; import { DocServer } from "../DocServer"; import { DocumentType } from "../documents/DocumentTypes"; -import { DictationManager } from "../util/DictationManager"; +import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { DragManager } from "../util/DragManager"; import { GroupManager } from "../util/GroupManager"; import { SelectionManager } from "../util/SelectionManager"; +import { SettingsManager } from "../util/SettingsManager"; import { SharingManager } from "../util/SharingManager"; import { SnappingManager } from "../util/SnappingManager"; import { undoBatch, UndoManager } from "../util/UndoManager"; @@ -27,8 +28,6 @@ import { LightboxView } from "./LightboxView"; import { MainView } from "./MainView"; import { DocumentLinksButton } from "./nodes/DocumentLinksButton"; import { AnchorMenu } from "./pdf/AnchorMenu"; -import { CurrentUserUtils } from "../util/CurrentUserUtils"; -import { SettingsManager } from "../util/SettingsManager"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -222,10 +221,13 @@ export class KeyManager { PromiseValue(Cast(Doc.UserDoc()["tabs-button-tools"], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); break; case "f": - const searchBtn = Doc.UserDoc().searchBtn as Doc; - - if (searchBtn) { - MainView.Instance.selectMenu(searchBtn); + if (SelectionManager.Views().length === 1 && SelectionManager.Views()[0].ComponentView?.search) { + SelectionManager.Views()[0].ComponentView?.search?.("", false, false); + } else { + const searchBtn = Doc.UserDoc().searchBtn as Doc; + if (searchBtn) { + MainView.Instance.selectMenu(searchBtn); + } } break; case "o": diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index be0b078ec..94cf1c5a6 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -902,7 +902,9 @@ export class CollectionFreeFormView extends CollectionSubView string; getScrollHeight?: () => number; + search?: (str:string, bwd?:boolean, clear?:boolean) => boolean; } export interface DocumentViewSharedProps { renderDepth: number; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index ce851b830..274d166f1 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -96,7 +96,17 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdfViewer?.search(string, fwd); + public search = action((searchString: string, bwd?: boolean, clear: boolean = false) => { + if (!this._searching && !clear) { + this._searching = true; + setTimeout(() => { + this._searchRef.current?.focus(); + this._searchRef.current?.select(); + this._searchRef.current?.setRangeText(searchString); + }); + } + return this._pdfViewer?.search(searchString, bwd, clear) || false; + }); public prevAnnotation = () => this._pdfViewer?.prevAnnotation(); public nextAnnotation = () => this._pdfViewer?.nextAnnotation(); public backPage = () => { this.Document._curPage = (this.Document._curPage || 1) - 1; return true; }; @@ -184,8 +194,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}>
+
+ +
; + } + searchStringChanged = (e: React.ChangeEvent) => 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); @@ -623,25 +666,7 @@ export class WebBox extends ViewBoxAnnotatableComponent
- {/*
- { - if (e.key === "Enter") { - (this._iframe?.contentWindow as any)?.find(e.target.value); - } - }} onChange={e => { - this._iframe?.contentWindow?.getSelection()?.empty(); - (this._iframe?.contentWindow as any)?.find(e.target.value) - }}> -
*/} + {!this.props.isContentActive() ? (null) : this.searchUI}
); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index d953c6b6c..7aa18e46f 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -125,12 +125,6 @@ export class PDFViewer extends React.Component { } }); - this._disposers.searchMatch = reaction(() => Doc.IsSearchMatch(this.props.rootDoc), - m => { - if (m) (this._lastSearch = true) && this.search(Doc.SearchQuery(), m.searchMatch > 0); - else !(this._lastSearch = false) && setTimeout(() => !this._lastSearch && this.search("", false, true), 200); - }, { fireImmediately: true }); - this._disposers.selected = reaction(() => this.props.isSelected(), selected => { // if (!selected) { @@ -337,10 +331,10 @@ export class PDFViewer extends React.Component { } @action - search = (searchString: string, fwd: boolean, clear: boolean = false) => { + search = (searchString: string, bwd?: boolean, clear: boolean = false) => { const findOpts = { caseSensitive: false, - findPrevious: !fwd, + findPrevious: bwd, highlightAll: true, phraseSearch: true, query: searchString @@ -348,7 +342,7 @@ export class PDFViewer extends React.Component { if (clear) { this._pdfViewer?.findController.executeCommand('reset', { query: "" }); } else if (!searchString) { - fwd ? this.nextAnnotation() : this.prevAnnotation(); + bwd ? this.prevAnnotation() : this.nextAnnotation(); } else if (this._pdfViewer?.pageViewsReady) { this._pdfViewer.findController.executeCommand('findagain', findOpts); } @@ -357,6 +351,7 @@ export class PDFViewer extends React.Component { this._mainCont.current.addEventListener("pagesloaded", executeFind); this._mainCont.current.addEventListener("pagerendered", executeFind); } + return true; } @action diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 9c353e9d0..3612bd7c4 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -104,9 +104,9 @@ export class SearchBox extends ViewBoxBaseComponent { - this.selectElement(doc); + onResultClick = action(async (doc: Doc) => { this._selectedResult = doc; + this.selectElement(doc, () => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, false)); }); makeLink = action((linkTo: Doc) => { @@ -269,8 +269,8 @@ export class SearchBox extends ViewBoxBaseComponent { - await DocumentManager.Instance.jumpToDocument(doc, true); + selectElement = async (doc: Doc, finishFunc: () => void) => { + await DocumentManager.Instance.jumpToDocument(doc, true, undefined, undefined, undefined, undefined, undefined, finishFunc); } /** @@ -307,7 +307,12 @@ export class SearchBox extends ViewBoxBaseComponent
{title}
}> -
this.makeLink(result[0]) : () => this.onResultClick(result[0])} className={className}> +
this.makeLink(result[0]) : + e => { + this.onResultClick(result[0]); + e.stopPropagation(); + }} className={className}>
{title}
-- cgit v1.2.3-70-g09d2 From 03c0caa35fa4ac63ac3efeb73de145ebd848cc54 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 16 Sep 2021 21:07:46 -0400 Subject: from last --- src/client/views/nodes/PDFBox.tsx | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 274d166f1..f0a502e31 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -117,11 +117,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent { let processed = false; switch (e.key) { - case "f": if (e.ctrlKey) { - setTimeout(() => this._searchRef.current?.focus(), 100); - this._searching = processed = true; - } - break; case "PageDown": processed = this.forwardPage(); break; case "PageUp": processed = this.backPage(); break; } -- cgit v1.2.3-70-g09d2 From e5e046fbf76dad34ef59754b9ed4c2469e5b849f Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 00:17:15 -0400 Subject: fixed being able to create inline (text selection) annotations on web pages --- src/client/views/nodes/WebBox.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index cb9256595..96a3ce83b 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -539,12 +539,10 @@ export class WebBox extends ViewBoxAnnotatableComponent - {this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => - ) - } -
; + return
+ {this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => + )} +
; } @computed get SidebarShown() { return this._showSidebar || this.layoutDoc._showSidebar ? true : false; } -- cgit v1.2.3-70-g09d2 From 1de71a39f1f6ebc2c909c92694db340cc9b256a0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 00:28:44 -0400 Subject: fixed keeping anchor menu visible when selecting a new marker color from menu --- src/client/views/nodes/WebBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 96a3ce83b..acccccfb4 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -224,7 +224,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { -- cgit v1.2.3-70-g09d2 From f5c4aa829955467c37ff35fb47b6d3c47fef4590 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 02:14:31 -0400 Subject: fixed right-drag marquee on webBox on Mac --- src/client/views/ContextMenu.tsx | 20 +++++++++++--------- src/client/views/MarqueeAnnotator.tsx | 6 +++--- src/client/views/nodes/WebBox.tsx | 26 ++++++++++++-------------- 3 files changed, 26 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 78564a11b..80ff16cf9 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -26,8 +26,7 @@ export class ContextMenu extends React.Component { @observable private _mouseX: number = -1; @observable private _mouseY: number = -1; @observable private _shouldDisplay: boolean = false; - @observable private _mouseDown: boolean = false; - + private _ignoreUp = false; private _reactionDisposer?: IReactionDisposer; constructor(props: Readonly<{}>) { @@ -36,17 +35,23 @@ export class ContextMenu extends React.Component { ContextMenu.Instance = this; } + public setIgnoreEvents(ignore: boolean) { + this._ignoreUp = ignore; + } + @action onPointerDown = (e: PointerEvent) => { - this._mouseDown = true; this._mouseX = e.clientX; this._mouseY = e.clientY; } @action onPointerUp = (e: PointerEvent) => { - this._mouseDown = false; const curX = e.clientX; const curY = e.clientY; + if (this._ignoreUp) { + this._ignoreUp = false; + return; + } if (Math.abs(this._mouseX - curX) > 1 || Math.abs(this._mouseY - curY) > 1) { this._shouldDisplay = false; } @@ -62,7 +67,7 @@ export class ContextMenu extends React.Component { componentWillUnmount() { document.removeEventListener("pointerdown", this.onPointerDown); document.removeEventListener("pointerup", this.onPointerUp); - this._reactionDisposer && this._reactionDisposer(); + this._reactionDisposer?.(); } @action @@ -70,10 +75,6 @@ export class ContextMenu extends React.Component { document.addEventListener("pointerdown", this.onPointerDown); document.addEventListener("pointerup", this.onPointerUp); - this._reactionDisposer = reaction( - () => this._shouldDisplay, - () => this._shouldDisplay && !this._mouseDown && runInAction(() => this._display = true) - ); } @action @@ -156,6 +157,7 @@ export class ContextMenu extends React.Component { this._searchString = initSearch; this._shouldDisplay = true; this._onDisplay = onDisplay; + this._display = !onDisplay; } @action diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 26e76090a..563261dec 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -31,7 +31,7 @@ export interface MarqueeAnnotatorProps { annotationLayer: HTMLDivElement; addDocument: (doc: Doc) => boolean; getPageFromScroll?: (top: number) => number; - finishMarquee: (x?: number, y?: number) => void; + finishMarquee: (x?: number, y?: number, PointerEvent?: PointerEvent) => void; anchorMenuClick?: () => undefined | ((anchor: Doc) => void); } @observer @@ -222,10 +222,10 @@ export class MarqueeAnnotator extends React.Component { if (AnchorMenu.Instance.Highlighting) {// when highlighter has been toggled when menu is pinned, we auto-highlight immediately on mouse up this.highlight("rgba(245, 230, 95, 0.75)", false); // yellowish highlight color for highlighted text (should match AnchorMenu's highlight color) } - this.props.finishMarquee(); + this.props.finishMarquee(undefined, undefined, e); } else { runInAction(() => this._width = this._height = 0); - this.props.finishMarquee(cliX, cliY); + this.props.finishMarquee(cliX, cliY, e); } } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index acccccfb4..9dafaadcb 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -247,20 +247,10 @@ export class WebBox extends ViewBoxAnnotatableComponent MarqueeAnnotator.clearAnnotations(this._savedAnnotations), false); } } - @action finishMarquee = (x?: number, y?: number) => { + @action finishMarquee = (x?: number, y?: number, e?: PointerEvent) => { this._marqueeing = undefined; this._isAnnotating = false; this._iframeClick = undefined; - x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false, false); + if (x !== undefined && y !== undefined) { + this._setPreviewCursor?.(x, y, false, false); + ContextMenu.Instance.closeMenu(); + ContextMenu.Instance.setIgnoreEvents(false); + if (e?.button === 2 || e?.ctrlKey) { + this.specificContextMenu(undefined as any); + this.props.docViewPath().lastElement().docView?.onContextMenu(undefined, x, y); + } + } } @computed get urlContent() { -- cgit v1.2.3-70-g09d2 From a5a4cc47944766a29e8b6dc2364c35de52c1400d Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 02:40:40 -0400 Subject: fixed top-down resizing of web pages and pdfs. turned off Cors option for novices. --- src/client/views/DocumentDecorations.tsx | 9 +++++---- src/client/views/nodes/WebBox.tsx | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6f9697703..3d6f157b6 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -280,6 +280,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P case "documentDecorations-topResizer": dY = -1; dH = -move[1]; + dragBottom = true; break; case "documentDecorations-bottomLeftResizer": dX = -1; @@ -387,10 +388,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => { Doc.GetProto(doc).data = new InkField(inkPts.map(ipt => // (new x — oldx) + newWidth * (oldxpoint /oldWidth) - ({ - X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width, - Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height - }))); + ({ + X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width, + Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height + }))); Doc.SetNativeWidth(doc, undefined); Doc.SetNativeHeight(doc, undefined); }); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 9dafaadcb..f230550e4 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -423,7 +423,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this.layoutDoc.useCors = !this.layoutDoc.useCors, icon: "snowflake" }); + !Doc.UserDoc().noviceMode && funcs.push({ description: (this.layoutDoc.useCors ? "Don't Use" : "Use") + " Cors", event: () => this.layoutDoc.useCors = !this.layoutDoc.useCors, icon: "snowflake" }); funcs.push({ description: (!this.layoutDoc.allowReflow ? "Allow" : "Prevent") + " Reflow", event: () => { const nw = !this.layoutDoc.allowReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.scaling?.() || 1); -- cgit v1.2.3-70-g09d2 From 582c709a2b08e2f6c12793121d0c8b264ddc2ca2 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 03:28:19 -0400 Subject: close context menu when starting a right-click drag on a webbox. .fixed dismissing marquee menu from outer view when clicking on nested webbox. AltKey drags marquee, not CtrlKey. --- .../views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index cedeb1112..ecff01e67 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -16,7 +16,7 @@ export class MarqueeOptionsMenu extends AntimodeMenu { public showMarquee: () => void = unimplementedFunction; public hideMarquee: () => void = unimplementedFunction; public pinWithView: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; - + public isShown = () => { return this._opacity > 0; } constructor(props: Readonly<{}>) { super(props); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index f230550e4..ca1b0d8ac 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -35,6 +35,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { LinkDocPreview } from "./LinkDocPreview"; import "./WebBox.scss"; import React = require("react"); +import { MarqueeOptionsMenu } from "../collections/collectionFreeForm"; const _global = (window /* browser */ || global /* node */) as any; const htmlToText = require("html-to-text"); @@ -247,9 +248,10 @@ export class WebBox extends ViewBoxAnnotatableComponent; return ( -
+
Date: Fri, 17 Sep 2021 04:13:34 -0400 Subject: fixed not inadvertently moving webBoxes after creating a marquee adn then clicking in the webBox, then clicking outside it. --- src/client/views/AntimodeMenu.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 8 ++++++-- src/client/views/nodes/WebBox.tsx | 7 ++++--- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx index fe6d39ca4..0f1fc6b69 100644 --- a/src/client/views/AntimodeMenu.tsx +++ b/src/client/views/AntimodeMenu.tsx @@ -16,7 +16,7 @@ export abstract class AntimodeMenu extends React.Co @observable protected _top: number = -300; @observable protected _left: number = -300; - @observable protected _opacity: number = 1; + @observable protected _opacity: number = 0; @observable protected _transitionProperty: string = "opacity"; @observable protected _transitionDuration: string = "0.5s"; @observable protected _transitionDelay: string = ""; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 187905960..46a8b6629 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -96,7 +96,7 @@ export interface DocComponentView { annotationKey?: string; getTitle?: () => string; getScrollHeight?: () => number; - search?: (str:string, bwd?:boolean, clear?:boolean) => boolean; + search?: (str: string, bwd?: boolean, clear?: boolean) => boolean; } export interface DocumentViewSharedProps { renderDepth: number; @@ -556,10 +556,14 @@ export class DocumentViewInternal extends DocComponent { + cleanupPointerEvents = () => { this.cleanUpInteractions(); document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); + } + + onPointerUp = (e: PointerEvent): void => { + this.cleanupPointerEvents(); if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index ca1b0d8ac..6a20ca14a 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -152,6 +152,7 @@ export class WebBox extends ViewBoxAnnotatableComponent disposer?.()); this._iframe?.removeEventListener('wheel', this.iframeWheel, true); + this._iframe?.contentDocument?.removeEventListener("pointerup", this.iframeUp); } @action @@ -215,8 +216,8 @@ export class WebBox extends ViewBoxAnnotatableComponent { + 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) { - this._iframe.contentDocument.addEventListener("pointerup", this.iframeUp); const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); const scale = (this.props.scaling?.() || 1) * mainContBounds.scale; const sel = this._iframe.contentWindow.getSelection(); @@ -237,7 +238,6 @@ export class WebBox extends ViewBoxAnnotatableComponent this._marqueeing = undefined), 100); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it. } else { this._iframeClick = this._iframe ?? undefined; @@ -267,6 +267,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { const iframe = this._iframe; + this._iframe?.contentDocument?.addEventListener("pointerup", this.iframeUp); if (iframe?.contentDocument) { iframe?.contentDocument.addEventListener("pointerdown", this.iframeDown); this._scrollHeight = Math.max(this.scrollHeight, iframe?.contentDocument.body.scrollHeight); @@ -457,7 +458,7 @@ export class WebBox extends ViewBoxAnnotatableComponent Date: Fri, 17 Sep 2021 14:07:09 -0400 Subject: added 'unset' docFilters. changed link doc views to use comparison box with title/caption. fixed linkEditor to write to data doc. generalized comparisonBox rendering to use parameterized fields. fixed pdf/web to honor pointerEvents none prop and fixed textAnnotations to get rendered once as an Annotation. moved filterIcon stuff into DocumentView --- src/Utils.ts | 4 +++- src/client/DocServer.ts | 2 ++ src/client/documents/Documents.ts | 17 +++++++++++------ src/client/views/collections/CollectionView.tsx | 12 ------------ .../collectionFreeForm/CollectionFreeFormLinkView.tsx | 6 +++--- src/client/views/linking/LinkEditor.tsx | 11 ++++++----- src/client/views/nodes/ComparisonBox.tsx | 8 +++++--- src/client/views/nodes/DocumentView.tsx | 19 +++++++++++++++++-- src/client/views/nodes/LinkBox.tsx | 19 ++++++------------- src/client/views/nodes/LinkDescriptionPopup.tsx | 7 ++++--- src/client/views/nodes/PDFBox.tsx | 9 ++++----- src/client/views/nodes/WebBox.tsx | 14 ++++++++------ src/client/views/pdf/Annotation.scss | 3 +++ src/client/views/pdf/PDFViewer.tsx | 13 +++++++------ src/fields/Doc.ts | 2 +- 15 files changed, 80 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/Utils.ts b/src/Utils.ts index 6eacd8296..e11f1154e 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -125,7 +125,9 @@ export namespace Utils { // bcz: isTransparent(__value__) is a hack. it would be nice to have acual functions be parsed, but now Doc.matchFieldValue is hardwired to recognize just this one return `backgroundColor:${isTransparentFunctionHack},${noRecursionHack}:x`;// bcz: hack. noRecursion should probably be either another ':' delimited field, or it should be a modifier to the comparision (eg., check, x, etc) field } - + export function PropUnsetFilter(prop: string) { + return `${prop}:any,${noRecursionHack}:unset`; + } export function toRGBAstr(col: { r: number, g: number, b: number, a?: number }) { return "rgba(" + col.r + "," + col.g + "," + col.b + (col.a !== undefined ? "," + col.a : "") + ")"; diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index e498a7cca..3b376a0e7 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -241,6 +241,7 @@ export namespace DocServer { // the field has been returned from the server const getSerializedField = Utils.EmitCallback(_socket, MessageStore.GetRefField, id); + console.log(id) // when the serialized RefField has been received, go head and begin deserializing it into an object. // Here, once deserialized, we also invoke .proto to 'load' the document's prototype, which ensures that all // future .proto calls on the Doc won't have to go farther than the cache to get their actual value. @@ -264,6 +265,7 @@ export namespace DocServer { } else { delete _cache[id]; } + console.log(id, field); return field; // either way, overwrite or delete any promises cached at this id (that we inserted as flags // to indicate that the field was in the process of being fetched). Now everything diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index f50f306a3..e8185400e 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -962,13 +962,17 @@ export namespace DocUtils { // metadata facets that exist const exists = Object.keys(facet).filter(value => facet[value] === "exists"); + // metadata facets that exist + const unsets = Object.keys(facet).filter(value => facet[value] === "unset"); + // facets that have an x next to them const xs = Object.keys(facet).filter(value => facet[value] === "x"); - if (!exists.length && !xs.length && !checks.length && !matches.length) return true; + if (!unsets.length && !exists.length && !xs.length && !checks.length && !matches.length) return true; const failsNotEqualFacets = !xs.length ? false : xs.some(value => Doc.matchFieldValue(d, facetKey, value)); const satisfiesCheckFacets = !checks.length ? true : checks.some(value => Doc.matchFieldValue(d, facetKey, value)); const satisfiesExistsFacets = !exists.length ? true : exists.some(value => d[facetKey] !== undefined); + const satisfiesUnsetsFacets = !unsets.length ? true : unsets.some(value => d[facetKey] === undefined); const satisfiesMatchFacets = !matches.length ? true : matches.some(value => { if (facetKey.startsWith("*")) { // fields starting with a '*' are used to match families of related fields. ie, *lastModified will match text-lastModified, data-lastModified, etc const allKeys = Array.from(Object.keys(d)); @@ -980,11 +984,11 @@ export namespace DocUtils { }); // if we're ORing them together, the default return is false, and we return true for a doc if it satisfies any one set of criteria if ((parentCollection?.currentFilter as Doc)?.filterBoolean === "OR") { - if (satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true; + if (satisfiesUnsetsFacets && satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true; } // if we're ANDing them together, the default return is true, and we return false for a doc if it doesn't satisfy any set of criteria else { - if (!satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false; + if (!satisfiesUnsetsFacets || !satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false; } } @@ -1088,10 +1092,11 @@ export namespace DocUtils { "anchor2-useLinkSmallAnchor": target.doc.useLinkSmallAnchor ? true : undefined, "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment, - layout_linkView: Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null), - linkDisplay: true, hidden: true, + linkDisplay: true, + hidden: true, linkRelationship, - _layoutKey: "layout_linkView", + _showCaption: "description", + _showTitle: "linkRelationship", description }, id), showPopup); } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 5c9c8063b..38e027fb3 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -246,12 +246,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null); @computed get childLayoutString() { return StrCast(this.rootDoc.childLayoutString); } - /** - * Shows the filter icon if it's a user-created collection which isn't a dashboard and has some docFilters applied on it or on the current dashboard. - */ - @computed get showFilterIcon() { - return this.props.Document.viewType !== CollectionViewType.Docking && !Doc.IsSystem(this.props.Document) && this._subView?.IsFiltered(); - } @observable _subView: any = undefined; @@ -280,12 +274,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent {this.showIsTagged()} {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)} - {this.showFilterIcon ? - { this.props.select(false); CurrentUserUtils.propertiesWidth = 250; e.stopPropagation(); })} - /> - : (null)}
); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 3b3e069d8..2cb487588 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -1,6 +1,6 @@ import { action, computed, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../../fields/Doc"; +import { Doc, Field } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; import { List } from "../../../../fields/List"; import { NumCast, StrCast } from "../../../../fields/Types"; @@ -180,7 +180,7 @@ export class CollectionFreeFormLinkView extends React.Component; const linkColorList = Doc.UserDoc().linkColorList as List; //access stroke color using index of the relationship in the color list (default black) @@ -189,7 +189,7 @@ export class CollectionFreeFormLinkView extends React.Component {textX === undefined ? (null) : - {StrCast(this.props.LinkDocs[0].description)} + {Field.toString(this.props.LinkDocs[0].description as any as Field)} } ); } diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 240a71c3e..219f7d3a2 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -2,13 +2,14 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Tooltip } from "@material-ui/core"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, StrListCast } from "../../../fields/Doc"; -import { DateCast, StrCast } from "../../../fields/Types"; +import { Doc, StrListCast, Field } from "../../../fields/Doc"; +import { DateCast, StrCast, Cast } from "../../../fields/Types"; import { LinkManager } from "../../util/LinkManager"; import { undoBatch } from "../../util/UndoManager"; import './LinkEditor.scss'; import { LinkRelationshipSearch } from "./LinkRelationshipSearch"; import React = require("react"); +import { ToString } from "../../../fields/FieldSymbols"; interface LinkEditorProps { @@ -20,7 +21,7 @@ interface LinkEditorProps { @observer export class LinkEditor extends React.Component { - @observable description = StrCast(LinkManager.currentLink?.description); + @observable description = Field.toString(LinkManager.currentLink?.description as any as Field); @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship); @observable openDropdown: boolean = false; @observable showInfo: boolean = false; @@ -41,7 +42,7 @@ export class LinkEditor extends React.Component { @undoBatch setRelationshipValue = action((value: string) => { if (LinkManager.currentLink) { - LinkManager.currentLink.linkRelationship = value; + Doc.GetProto(LinkManager.currentLink).linkRelationship = value; const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList); const linkColorList = StrListCast(Doc.UserDoc().linkColorList); // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color @@ -79,7 +80,7 @@ export class LinkEditor extends React.Component { @undoBatch setDescripValue = action((value: string) => { if (LinkManager.currentLink) { - LinkManager.currentLink.description = value; + Doc.GetProto(LinkManager.currentLink).description = value; this.buttonColor = "rgb(62, 133, 55)"; setTimeout(action(() => this.buttonColor = ""), 750); return true; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 6708a08ee..72c7e4f45 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -15,6 +15,7 @@ import "./ComparisonBox.scss"; import { DocumentView, DocumentViewProps } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import React = require("react"); +import { DocumentType } from '../../documents/DocumentTypes'; export const comparisonSchema = createSchema({}); @@ -87,7 +88,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent; }; const displayDoc = (which: string) => { - const whichDoc = Cast(this.dataDoc[`compareBox-${which}`], Doc, null); + var whichDoc = Cast(this.dataDoc[which], Doc, null); + if (whichDoc.type === DocumentType.MARKER) whichDoc = Cast(whichDoc.annotationOn, Doc, null); return whichDoc ? <> - {displayBox("after", 1, this.props.PanelWidth() - 3)} + {displayBox(this.fieldKey === "data" ? "compareBox-after" : `${this.fieldKey}2`, 1, this.props.PanelWidth() - 3)}
- {displayBox("before", 0, 0)} + {displayBox(this.fieldKey === "data" ? "compareBox-before" : `${this.fieldKey}1`, 0, 0)}
(this.props.PanelWidth() - 5) / this.props.PanelWidth() ? "w-resize" : undefined }} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 46a8b6629..35249c7f4 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -13,7 +13,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Ty import { AudioField } from "../../../fields/URLField"; import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util'; import { MobileInterface } from '../../../mobile/MobileInterface'; -import { emptyFunction, hasDescendantTarget, OmitKeys, returnTrue, returnVal, Utils, lightOrDark, simulateMouseClick } from "../../../Utils"; +import { emptyFunction, hasDescendantTarget, OmitKeys, returnTrue, returnVal, Utils, lightOrDark, simulateMouseClick, returnEmptyString } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentType } from '../../documents/DocumentTypes'; @@ -802,6 +802,12 @@ export class DocumentViewInternal extends DocComponent StrListCast(this.props.Document._docFilters); + collectionRangeDocFilters = () => StrListCast(this.props.Document._docRangeFilters); + @computed get showFilterIcon() { + return this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" : + this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined + } rootSelected = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; panelHeight = () => this.props.PanelHeight() - this.headerMargin; screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin); @@ -832,7 +838,7 @@ export class DocumentViewInternal extends DocComponent; return
this.props.PanelHeight() || 1; anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { switch (property) { + case StyleProp.ShowTitle: return ""; case StyleProp.PointerEvents: return "none"; case StyleProp.LinkSource: return this.props.Document;// pass the LinkSource to the LinkAnchorBox default: return this.props.styleProvider?.(doc, props, property); @@ -901,6 +908,8 @@ export class DocumentViewInternal extends DocComponent } + {this.showFilterIcon ? + { this.props.select(false); CurrentUserUtils.propertiesWidth = 250; e.stopPropagation(); })} + /> + : (null)}
; } } diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 55ea45bb8..b82d16677 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -2,10 +2,10 @@ import React = require("react"); import { observer } from "mobx-react"; import { documentSchema } from "../../../fields/documentSchemas"; import { makeInterface } from "../../../fields/Schema"; -import { returnFalse } from "../../../Utils"; -import { CollectionTreeView } from "../collections/CollectionTreeView"; +import { emptyFunction, returnFalse } from "../../../Utils"; import { ViewBoxBaseComponent } from "../DocComponent"; import { StyleProp } from "../StyleProvider"; +import { ComparisonBox } from "./ComparisonBox"; import { FieldView, FieldViewProps } from './FieldView'; import "./LinkBox.scss"; @@ -20,22 +20,15 @@ export class LinkBox extends ViewBoxBaseComponent( if (this.dataDoc.treeViewOpen === undefined) setTimeout(() => this.dataDoc.treeViewOpen = true); return
- - + moveDocument={returnFalse} />
; } } \ No newline at end of file diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index b62a4dd56..a9d33f161 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -1,8 +1,9 @@ import React = require("react"); +import { action, observable } from "mobx"; import { observer } from "mobx-react"; -import "./LinkDescriptionPopup.scss"; -import { observable, action } from "mobx"; +import { Doc } from "../../../fields/Doc"; import { LinkManager } from "../../util/LinkManager"; +import "./LinkDescriptionPopup.scss"; import { TaskCompletionBox } from "./TaskCompletedBox"; @@ -25,7 +26,7 @@ export class LinkDescriptionPopup extends React.Component<{}> { onDismiss = (add: boolean) => { LinkDescriptionPopup.descriptionPopup = false; if (add) { - LinkManager.currentLink && (LinkManager.currentLink.description = this.description); + LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).description = this.description); } } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index f0a502e31..30b4dc92a 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -3,9 +3,9 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction import { observer } from "mobx-react"; import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; -import { Doc, DocListCast, Opt, WidthSym } from "../../../fields/Doc"; +import { Doc, DocListCast, Opt, WidthSym, StrListCast } from "../../../fields/Doc"; import { documentSchema } from '../../../fields/documentSchemas'; -import { makeInterface } from "../../../fields/Schema"; +import { makeInterface, listSpec } from "../../../fields/Schema"; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { PdfField } from "../../../fields/URLField"; import { TraceMobx } from '../../../fields/util'; @@ -25,6 +25,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; import React = require("react"); +import { CurrentUserUtils } from '../../util/CurrentUserUtils'; type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>; const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @@ -249,9 +250,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { - return 1; - } + contentScaling = () => 1; @computed get renderPdfView() { TraceMobx(); const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 6a20ca14a..60a83d612 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -532,7 +532,8 @@ export class WebBox extends ViewBoxAnnotatableComponent {this.urlContent}
; @@ -575,10 +576,11 @@ export class WebBox extends ViewBoxAnnotatableComponent 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; - transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()]; - opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()]; + basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter("textInlineAnnotations")]; + transparentFilter = () => [Utils.IsTransparentFilter(), ...this.basicFilter()]; + opaqueFilter = () => [Utils.IsOpaqueFilter(), ...this.basicFilter()]; render() { - const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined; + const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : this.props.pointerEvents ? this.props.pointerEvents as any : undefined; const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; const scale = previewScale * (this.props.scaling?.() || 1); const renderAnnotations = (docFilters?: () => string[]) => @@ -593,7 +595,7 @@ export class WebBox extends ViewBoxAnnotatableComponent; return (
+ style={{ pointerEvents: this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none" }} >
{ let focusSpeed: Opt; if (doc !== this.props.rootDoc && mainCont) { const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1); - const scrollTo = 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); if (scrollTo !== undefined) { focusSpeed = 500; @@ -502,8 +502,9 @@ export class PDFViewer extends React.Component { overlayTransform = () => this.scrollXf().scale(1 / this._zoomed); panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1); // (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); - transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()]; - opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()]; + basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter("textInlineAnnotations")]; + transparentFilter = () => [Utils.IsTransparentFilter(), ...this.basicFilter()]; + opaqueFilter = () => [Utils.IsOpaqueFilter(), ...this.basicFilter()]; @computed get overlayLayer() { const renderAnnotations = (docFilters?: () => string[]) => { select={emptyFunction} ContentScaling={this.contentZoom} bringToFront={emptyFunction} - docFilters={docFilters || this.props.docFilters} + docFilters={docFilters || this.basicFilter} dontRenderDocuments={docFilters ? false : true} CollectionView={undefined} ScreenToLocalTransform={this.overlayTransform} @@ -543,7 +544,7 @@ export class PDFViewer extends React.Component {
; } @computed get pdfViewerDiv() { - return
; + return
; } @computed get contentScaling() { return this.props.ContentScaling?.() || 1; } @computed get standinViews() { @@ -556,7 +557,7 @@ export class PDFViewer extends React.Component { render() { TraceMobx(); return
-
, key: string, value: any, modifiers: "remove" | "match" | "check" | "x" | "exists", toggle?: boolean, fieldSuffix?: string, append: boolean = true) { + export function setDocFilter(container: Opt, key: string, value: any, modifiers: "remove" | "match" | "check" | "x" | "exists" | "unset", toggle?: boolean, fieldSuffix?: string, append: boolean = true) { if (!container) return; const filterField = "_" + (fieldSuffix ? fieldSuffix + "-" : "") + "docFilters"; const docFilters = Cast(container[filterField], listSpec("string"), []); -- cgit v1.2.3-70-g09d2 From 50886bf908a5a155849daa5920b42a86752f9d1b Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 15:09:55 -0400 Subject: fixed warnings --- src/client/DocServer.ts | 2 -- src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 3b376a0e7..e498a7cca 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -241,7 +241,6 @@ export namespace DocServer { // the field has been returned from the server const getSerializedField = Utils.EmitCallback(_socket, MessageStore.GetRefField, id); - console.log(id) // when the serialized RefField has been received, go head and begin deserializing it into an object. // Here, once deserialized, we also invoke .proto to 'load' the document's prototype, which ensures that all // future .proto calls on the Doc won't have to go farther than the cache to get their actual value. @@ -265,7 +264,6 @@ export namespace DocServer { } else { delete _cache[id]; } - console.log(id, field); return field; // either way, overwrite or delete any promises cached at this id (that we inserted as flags // to indicate that the field was in the process of being fetched). Now everything diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index ecff01e67..71642216c 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -16,7 +16,7 @@ export class MarqueeOptionsMenu extends AntimodeMenu { public showMarquee: () => void = unimplementedFunction; public hideMarquee: () => void = unimplementedFunction; public pinWithView: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; - public isShown = () => { return this._opacity > 0; } + public isShown = () => this._opacity > 0; constructor(props: Readonly<{}>) { super(props); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 35249c7f4..d2b4b0348 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -806,7 +806,7 @@ export class DocumentViewInternal extends DocComponent StrListCast(this.props.Document._docRangeFilters); @computed get showFilterIcon() { return this.collectionFilters().length || this.collectionRangeDocFilters().length ? "hasFilter" : - this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined + this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? "inheritsFilter" : undefined; } rootSelected = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; panelHeight = () => this.props.PanelHeight() - this.headerMargin; -- cgit v1.2.3-70-g09d2 From b4a3dd6551a0ad6582c2a1a42168faae74ef1913 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 16:09:31 -0400 Subject: fixed link lines to text selections in PDF/Web. fixed pointer Events for anchor in PDF/Web to be active when doc is active. --- src/client/views/nodes/WebBox.tsx | 22 ++++++++++++++++------ src/client/views/pdf/Annotation.tsx | 5 ++++- src/client/views/pdf/PDFViewer.tsx | 23 +++++++++++++++++------ 3 files changed, 37 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 60a83d612..8e6586735 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -20,6 +20,7 @@ import { KeyCodes } from "../../util/KeyCodes"; import { Scripting } from "../../util/Scripting"; import { SnappingManager } from "../../util/SnappingManager"; import { undoBatch } from "../../util/UndoManager"; +import { MarqueeOptionsMenu } from "../collections/collectionFreeForm"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; @@ -31,11 +32,12 @@ import { MarqueeAnnotator } from "../MarqueeAnnotator"; import { AnchorMenu } from "../pdf/AnchorMenu"; import { Annotation } from "../pdf/Annotation"; import { SidebarAnnos } from "../SidebarAnnos"; +import { StyleProp } from "../StyleProvider"; +import { DocumentViewProps } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { LinkDocPreview } from "./LinkDocPreview"; import "./WebBox.scss"; import React = require("react"); -import { MarqueeOptionsMenu } from "../collections/collectionFreeForm"; const _global = (window /* browser */ || global /* node */) as any; const htmlToText = require("html-to-text"); @@ -541,9 +543,10 @@ export class WebBox extends ViewBoxAnnotatableComponent {this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => - )} + )}
; } @@ -577,8 +580,15 @@ export class WebBox extends ViewBoxAnnotatableComponent this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop)); anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter("textInlineAnnotations")]; - transparentFilter = () => [Utils.IsTransparentFilter(), ...this.basicFilter()]; - opaqueFilter = () => [Utils.IsOpaqueFilter(), ...this.basicFilter()]; + transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()]; + opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()]; + childStyleProvider = (doc: (Doc | undefined), props: Opt, property: string): any => { + if (doc instanceof Doc && property === StyleProp.PointerEvents) { + if (doc.textInlineAnnotations) return "none"; + } + return this.props.styleProvider?.(doc, props, property); + } + pointerEvents = () => this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none"; render() { const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : this.props.pointerEvents ? this.props.pointerEvents as any : undefined; const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; @@ -604,11 +614,11 @@ export class WebBox extends ViewBoxAnnotatableComponent; return (
+ style={{ pointerEvents: this.pointerEvents() }} >
) => void; + pointerEvents?: string; } @observer export class Annotation extends React.Component { render() { - return DocListCast(this.props.anno.textInlineAnnotations).map(a => ); + return DocListCast(this.props.anno.textInlineAnnotations).map(a => ); } } interface IRegionAnnotationProps extends IAnnotationProps { document: Doc; + pointerEvents?: string; } @observer class RegionAnnotation extends React.Component { @@ -96,6 +98,7 @@ class RegionAnnotation extends React.Component { width: NumCast(this.props.document._width), height: NumCast(this.props.document._height), opacity: this._brushed ? 0.5 : undefined, + pointerEvents: this.props.pointerEvents as any, backgroundColor: this._brushed ? "orange" : StrCast(this.props.document.backgroundColor), }} >
); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 78adedf5b..3f7f38bdf 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -16,10 +16,13 @@ import { CompiledScript, CompileScript } from "../../util/Scripting"; import { SelectionManager } from "../../util/SelectionManager"; import { SharingManager } from "../../util/SharingManager"; import { SnappingManager } from "../../util/SnappingManager"; +import { MarqueeOptionsMenu } from "../collections/collectionFreeForm"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { MarqueeAnnotator } from "../MarqueeAnnotator"; +import { DocumentViewProps } from "../nodes/DocumentView"; import { FieldViewProps } from "../nodes/FieldView"; import { LinkDocPreview } from "../nodes/LinkDocPreview"; +import { StyleProp } from "../StyleProvider"; import { AnchorMenu } from "./AnchorMenu"; import { Annotation } from "./Annotation"; import "./PDFViewer.scss"; @@ -481,11 +484,12 @@ export class PDFViewer extends React.Component { } } + pointerEvents = () => this.props.isContentActive() && this.props.pointerEvents !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none"; @computed get annotationLayer() { + const pe = this.pointerEvents(); return
{this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno => - ) - } + )}
; } @@ -503,8 +507,15 @@ export class PDFViewer extends React.Component { panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1); // (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); basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter("textInlineAnnotations")]; - transparentFilter = () => [Utils.IsTransparentFilter(), ...this.basicFilter()]; - opaqueFilter = () => [Utils.IsOpaqueFilter(), ...this.basicFilter()]; + transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()]; + opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()]; + childStyleProvider = (doc: (Doc | undefined), props: Opt, property: string): any => { + if (doc instanceof Doc && property === StyleProp.PointerEvents) { + if (doc.textInlineAnnotations) return "none"; + return "all"; + } + return this.props.styleProvider?.(doc, props, property); + } @computed get overlayLayer() { const renderAnnotations = (docFilters?: () => string[]) => { ContentScaling={this.contentZoom} bringToFront={emptyFunction} docFilters={docFilters || this.basicFilter} + styleProvider={this.childStyleProvider} dontRenderDocuments={docFilters ? false : true} CollectionView={undefined} ScreenToLocalTransform={this.overlayTransform} - renderDepth={this.props.renderDepth + 1} - childPointerEvents={true} />; + renderDepth={this.props.renderDepth + 1} />; return
Date: Fri, 17 Sep 2021 17:51:46 -0400 Subject: fixed following links to documents in sidebars that haven't been opened to still open the sidebar and show the document. required a change to how ProxyFields set field promises and use field caches. --- src/client/views/SidebarAnnos.tsx | 2 +- src/fields/Proxy.ts | 66 ++++++--------------------------------- 2 files changed, 11 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 659eb86d1..6a5b0a3ae 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -68,8 +68,8 @@ export class SidebarAnnos extends React.Component { if (DocListCast(this.props.rootDoc[this.sidebarKey]).includes(doc)) { if (this.props.layoutDoc[this.filtersKey]) { this.props.layoutDoc[this.filtersKey] = new List(); - return true; } + return true; } return false; } diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts index 62734d3d2..07553f17c 100644 --- a/src/fields/Proxy.ts +++ b/src/fields/Proxy.ts @@ -9,72 +9,33 @@ import { Id, Copy, ToScriptString, ToString } from "./FieldSymbols"; import { scriptingGlobal } from "../client/util/Scripting"; import { Plugins } from "./util"; -function deserializeProxy(field: any) { - if (!field.cache) { - field.cache = DocServer.GetCachedRefField(field.fieldId) as any; - } -} -@Deserializable("proxy", deserializeProxy) +@Deserializable("proxy") export class ProxyField extends ObjectField { constructor(); constructor(value: T); constructor(fieldId: string); constructor(value?: T | string) { super(); - if (typeof value === "string") { - this.cache = DocServer.GetCachedRefField(value) as any; - this.fieldId = value; - } else if (value) { - this.cache = value; - this.fieldId = value[Id]; - } - } - - [Copy]() { - if (this.cache) return new ProxyField(this.cache); - return new ProxyField(this.fieldId); + this.fieldId = typeof value === "string" ? value : (value?.[Id] ?? ""); } - [ToScriptString]() { - return "invalid"; - } - [ToString]() { - return "ProxyField"; - } + [Copy]() { return new ProxyField((this.cache ?? this.fieldId) as T); } + [ToScriptString]() { return "invalid"; } + [ToString]() { return "ProxyField"; } @serializable(primitive()) readonly fieldId: string = ""; - - // This getter/setter and nested object thing is - // because mobx doesn't play well with observable proxies - @observable.ref - private _cache: { readonly field: T | undefined } = { field: undefined }; - private get cache(): T | undefined { - return this._cache.field; - } - private set cache(field: T | undefined) { - this._cache = { field }; - } - private failed = false; private promise?: Promise; + private get cache(): T | undefined { return DocServer.GetCachedRefField(this.fieldId) as T } + value(): T | undefined | FieldWaiting { - if (this.cache) { - return this.cache; - } - if (this.failed) { - return undefined; - } + if (this.cache) return this.cache; + if (this.failed) return undefined; if (!this.promise) { - const cached = DocServer.GetCachedRefField(this.fieldId); - if (cached !== undefined) { - runInAction(() => this.cache = cached as any); - return cached as any; - } this.promise = DocServer.GetRefField(this.fieldId).then(action((field: any) => { this.promise = undefined; - this.cache = field; if (field === undefined) this.failed = true; return field; })); @@ -83,14 +44,7 @@ export class ProxyField extends ObjectField { } promisedValue(): string { return !this.cache && !this.failed && !this.promise ? this.fieldId : ""; } setPromise(promise: any) { - this.promise = promise; - } - @action - setValue(field: any) { - this.promise = undefined; - this.cache = field; - if (field === undefined) this.failed = true; - return field; + if (this.cache === undefined) this.promise = promise; } } -- cgit v1.2.3-70-g09d2 From 7e3bb99b81dd9494c927abacc2ebf920282f3ccb Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 19:13:23 -0400 Subject: reverting last change. --- src/fields/Proxy.ts | 66 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts index 07553f17c..62734d3d2 100644 --- a/src/fields/Proxy.ts +++ b/src/fields/Proxy.ts @@ -9,33 +9,72 @@ import { Id, Copy, ToScriptString, ToString } from "./FieldSymbols"; import { scriptingGlobal } from "../client/util/Scripting"; import { Plugins } from "./util"; -@Deserializable("proxy") +function deserializeProxy(field: any) { + if (!field.cache) { + field.cache = DocServer.GetCachedRefField(field.fieldId) as any; + } +} +@Deserializable("proxy", deserializeProxy) export class ProxyField extends ObjectField { constructor(); constructor(value: T); constructor(fieldId: string); constructor(value?: T | string) { super(); - this.fieldId = typeof value === "string" ? value : (value?.[Id] ?? ""); + if (typeof value === "string") { + this.cache = DocServer.GetCachedRefField(value) as any; + this.fieldId = value; + } else if (value) { + this.cache = value; + this.fieldId = value[Id]; + } + } + + [Copy]() { + if (this.cache) return new ProxyField(this.cache); + return new ProxyField(this.fieldId); } - [Copy]() { return new ProxyField((this.cache ?? this.fieldId) as T); } - [ToScriptString]() { return "invalid"; } - [ToString]() { return "ProxyField"; } + [ToScriptString]() { + return "invalid"; + } + [ToString]() { + return "ProxyField"; + } @serializable(primitive()) readonly fieldId: string = ""; + + // This getter/setter and nested object thing is + // because mobx doesn't play well with observable proxies + @observable.ref + private _cache: { readonly field: T | undefined } = { field: undefined }; + private get cache(): T | undefined { + return this._cache.field; + } + private set cache(field: T | undefined) { + this._cache = { field }; + } + private failed = false; private promise?: Promise; - private get cache(): T | undefined { return DocServer.GetCachedRefField(this.fieldId) as T } - value(): T | undefined | FieldWaiting { - if (this.cache) return this.cache; - if (this.failed) return undefined; + if (this.cache) { + return this.cache; + } + if (this.failed) { + return undefined; + } if (!this.promise) { + const cached = DocServer.GetCachedRefField(this.fieldId); + if (cached !== undefined) { + runInAction(() => this.cache = cached as any); + return cached as any; + } this.promise = DocServer.GetRefField(this.fieldId).then(action((field: any) => { this.promise = undefined; + this.cache = field; if (field === undefined) this.failed = true; return field; })); @@ -44,7 +83,14 @@ export class ProxyField extends ObjectField { } promisedValue(): string { return !this.cache && !this.failed && !this.promise ? this.fieldId : ""; } setPromise(promise: any) { - if (this.cache === undefined) this.promise = promise; + this.promise = promise; + } + @action + setValue(field: any) { + this.promise = undefined; + this.cache = field; + if (field === undefined) this.failed = true; + return field; } } -- cgit v1.2.3-70-g09d2 From 75c47275853bfe422d6ae8a53be8ffe1996e1e76 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 19:46:42 -0400 Subject: more conservative fix for previous. --- src/fields/Proxy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts index 62734d3d2..f01b502c9 100644 --- a/src/fields/Proxy.ts +++ b/src/fields/Proxy.ts @@ -79,7 +79,7 @@ export class ProxyField extends ObjectField { return field; })); } - return this.promise as any; + return DocServer.GetCachedRefField(this.fieldId) ?? (this.promise as any); } promisedValue(): string { return !this.cache && !this.failed && !this.promise ? this.fieldId : ""; } setPromise(promise: any) { -- cgit v1.2.3-70-g09d2 From fcab3f96513c759ca67281e871b970d5691348af Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 20:12:00 -0400 Subject: fixed making link to selected region in video --- src/client/views/collections/CollectionStackedTimeline.tsx | 5 +++-- src/client/views/nodes/VideoBox.tsx | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 65022fdfd..89da6692a 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -372,10 +372,11 @@ export class CollectionStackedTimeline extends CollectionSubView< startTag: string, endTag: string, anchorStartTime?: number, - anchorEndTime?: number + anchorEndTime?: number, + docAnchor?: Doc ) { if (anchorStartTime === undefined) return rootDoc; - const anchor = Docs.Create.LabelDocument({ + const anchor = docAnchor ?? Docs.Create.LabelDocument({ title: ComputedField.MakeFunction( `"#" + formatToTime(self["${startTag}"]) + "-" + formatToTime(self["${endTag}"])` ) as any, diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 90de3227f..e3ba638b3 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -30,6 +30,7 @@ import { DragManager } from "../../util/DragManager"; import { DocumentManager } from "../../util/DocumentManager"; import { DocumentType } from "../../documents/DocumentTypes"; import { Tooltip } from "@material-ui/core"; +import { AnchorMenu } from "../pdf/AnchorMenu"; const path = require('path'); type VideoDocument = makeInterface<[typeof documentSchema]>; @@ -74,7 +75,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent { const timecode = Cast(this.layoutDoc._currentTimecode, "number", null); - return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, "_timecodeToShow"/* videoStart */, "_timecodeToHide" /* videoEnd */, timecode ? timecode : undefined) || this.rootDoc; + const marquee = AnchorMenu.Instance.GetAnchor?.(); + return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, "_timecodeToShow"/* videoStart */, "_timecodeToHide" /* videoEnd */, timecode ? timecode : undefined, undefined, marquee) || this.rootDoc; } videoLoad = () => { -- cgit v1.2.3-70-g09d2 From dfe45d9162857b35574f8f809bca132c0467189a Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 20:37:52 -0400 Subject: fixed setting time of audio doc when clicking on audiotag in RTF. --- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 3c2ff2df5..3e5c4456c 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1187,9 +1187,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if ((e.target as any).tagName === "AUDIOTAG") { e.preventDefault(); e.stopPropagation(); + const timecode = Number((e.target as any)?.dataset?.timecode); DocServer.GetRefField((e.target as any)?.dataset?.audioid || 0).then(anchor => { if (anchor instanceof Doc) { - const timecode = NumCast(anchor.timecodeToShow, 0); + // const timecode = NumCast(anchor.timecodeToShow, 0); const audiodoc = anchor.annotationOn as Doc; const func = () => { const docView = DocumentManager.Instance.getDocumentView(audiodoc); -- cgit v1.2.3-70-g09d2 From ace42c6705d9f523f6f7af8cc22d0e6a3b5eeace Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 17 Sep 2021 21:33:24 -0400 Subject: stop propagation of keybaord events in EquationBox to allow cursor controls w/o moving the document --- src/client/views/nodes/EquationBox.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index dacafcdf4..11ef6562f 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -88,6 +88,7 @@ export class EquationBox extends ViewBoxBaseComponent e.stopPropagation()} > Date: Mon, 20 Sep 2021 10:45:28 -0400 Subject: changed link previews to show document, not context, unless document is a marker. de select documentViews when unmounted. --- src/client/util/DocumentManager.ts | 2 ++ src/client/views/nodes/LinkDocPreview.tsx | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index dfec9823b..b66befb08 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -10,6 +10,7 @@ import { LightboxView } from '../views/LightboxView'; import { DocumentView, ViewAdjustment } from '../views/nodes/DocumentView'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; import { Scripting } from './Scripting'; +import { SelectionManager } from './SelectionManager'; export class DocumentManager { @@ -62,6 +63,7 @@ export class DocumentManager { const index = this.DocumentViews.indexOf(view); index !== -1 && this.DocumentViews.splice(index, 1); } + SelectionManager.DeselectView(view); }); //gets all views diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 126a37eb8..424083dac 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -4,7 +4,7 @@ import { action, computed, observable } from 'mobx'; import { observer } from "mobx-react"; import wiki from "wikijs"; import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocCastAsync } from "../../../fields/Doc"; -import { NumCast, StrCast } from "../../../fields/Types"; +import { NumCast, StrCast, Cast } from "../../../fields/Types"; import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, setupMoveUpEvents, Utils } from "../../../Utils"; import { DocServer } from '../../DocServer'; import { Docs, DocUtils } from "../../documents/Documents"; @@ -14,6 +14,7 @@ import { undoBatch } from '../../util/UndoManager'; import { DocumentView, DocumentViewSharedProps } from "./DocumentView"; import './LinkDocPreview.scss'; import React = require("react"); +import { DocumentType } from '../../documents/DocumentTypes'; interface LinkDocPreviewProps { linkDoc?: Doc; @@ -85,7 +86,7 @@ export class LinkDocPreview extends React.Component { this._linkDoc = DocListCast(anchor.links)[0]; this._linkSrc = anchor; const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc); - this._targetDoc = linkTarget?.annotationOn as Doc ?? linkTarget; + this._targetDoc = linkTarget?.type === DocumentType.MARKER && linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget; this._toolTipText = ""; } })); -- cgit v1.2.3-70-g09d2 From 240f2c9bda4a9a32d84d1de93820f6fbc8eef458 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 Sep 2021 12:24:34 -0400 Subject: fixed equations/ink to work properly when not fitwidth in lightbox. don't show titles for ink or equations using fields now. --- src/client/documents/Documents.ts | 8 +++++--- src/client/views/DocumentDecorations.tsx | 20 ++++++++++-------- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/EquationBox.scss | 3 +++ src/client/views/nodes/EquationBox.tsx | 7 ++++++- .../views/nodes/formattedText/FormattedTextBox.tsx | 24 ++++++++++------------ 6 files changed, 37 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e8185400e..fafbc4a7d 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -430,7 +430,7 @@ export namespace Docs { }], [DocumentType.EQUATION, { layout: { view: EquationBox, dataField: defaultDataKey }, - options: { links: ComputedField.MakeFunction("links(self)") as any } + options: { links: ComputedField.MakeFunction("links(self)") as any, hideResizeHandles: true, hideDecorationTitle: true } }], [DocumentType.FUNCPLOT, { layout: { view: FunctionPlotBox, dataField: defaultDataKey }, @@ -463,9 +463,9 @@ export namespace Docs { layout: { view: CollectionView, dataField: defaultDataKey }, options: { links: ComputedField.MakeFunction("links(self)") as any, hideLinkButton: true } }], - [DocumentType.INK, { + [DocumentType.INK, { // NOTE: this is unused!! ink fields are filled in directly within the InkDocument() method layout: { view: InkingStroke, dataField: defaultDataKey }, - options: { _fontFamily: "cursive", backgroundColor: "transparent", links: ComputedField.MakeFunction("links(self)") as any } + options: { links: ComputedField.MakeFunction("links(self)") as any } }], [DocumentType.SCREENSHOT, { layout: { view: ScreenshotBox, dataField: defaultDataKey }, @@ -716,6 +716,8 @@ export namespace Docs { I.type = DocumentType.INK; I.layout = InkingStroke.LayoutString("data"); I.color = color; + I.hideDecorationTitle = true; // don't show title when selected + I.hideOpenButton = true; // don't show open full screen button when selected I.fillColor = fillColor; I.strokeWidth = strokeWidth; I.strokeBezier = strokeBezier; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3d6f157b6..d785d5419 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -388,10 +388,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => { Doc.GetProto(doc).data = new InkField(inkPts.map(ipt => // (new x — oldx) + newWidth * (oldxpoint /oldWidth) - ({ - X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width, - Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height - }))); + ({ + X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width, + Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height + }))); Doc.SetNativeWidth(doc, undefined); Doc.SetNativeHeight(doc, undefined); }); @@ -421,7 +421,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P if (SnappingManager.GetIsDragging() || bounds.r - bounds.x < 1 || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) { return (null); } - const canOpen = SelectionManager.Views().some(docView => !docView.props.Document._stayInCollection && !docView.props.Document.isGroup); + const hideResizers = seldoc.props.hideResizeHandles || seldoc.rootDoc.hideResizeHandles; + const hideTitle = seldoc.props.hideDecorationTitle || seldoc.rootDoc.hideDecorationTitle; + const canOpen = SelectionManager.Views().some(docView => !docView.props.Document._stayInCollection && !docView.props.Document.isGroup && !docView.props.Document.hideOpenButton); const canDelete = SelectionManager.Views().some(docView => { const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit; return (!docView.rootDoc._stayInCollection || docView.rootDoc.isInkMask) && @@ -473,12 +475,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight, }}> {!canDelete ?
: topBtn("close", "times", undefined, this.onCloseClick, "Close")} - {seldoc.props.hideDecorationTitle || seldoc.props.Document.type === DocumentType.EQUATION ? (null) : titleArea} - {seldoc.props.hideResizeHandles || seldoc.props.Document.type === DocumentType.EQUATION ? (null) : + {hideTitle ? (null) : titleArea}{!canOpen ? (null) : topBtn("open", "external-link-alt", this.onMaximizeDown, undefined, "Open in Tab (ctrl: as alias, shift: in new collection)")} + + {hideResizers ? (null) : <> - {SelectionManager.Views().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) : + {SelectionManager.Views().length !== 1 || hideTitle ? (null) : topBtn("iconify", `window-${seldoc.finalLayoutKey.includes("icon") ? "restore" : "minimize"}`, undefined, this.onIconifyClick, `${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`)} - {!canOpen ? (null) : topBtn("open", "external-link-alt", this.onMaximizeDown, undefined, "Open in Tab (ctrl: as alias, shift: in new collection)")}
e.preventDefault()} />
e.preventDefault()} />
e.preventDefault()} /> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d2b4b0348..60ceac007 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1168,7 +1168,7 @@ export class DocumentView extends React.Component { } const xf = (this.docView?.props.ScreenToLocalTransform().scale(this.nativeScaling)).inverse(); const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)]; - if (this.docView.props.LayoutTemplateString?.includes("LinkAnchorBox")) { + if (this.docView.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { const docuBox = this.docView.ContentDiv.getElementsByClassName("linkAnchorBox-cont"); if (docuBox.length) return docuBox[0].getBoundingClientRect(); } diff --git a/src/client/views/nodes/EquationBox.scss b/src/client/views/nodes/EquationBox.scss index e69de29bb..6c9d53d10 100644 --- a/src/client/views/nodes/EquationBox.scss +++ b/src/client/views/nodes/EquationBox.scss @@ -0,0 +1,3 @@ +.equationBox-cont { + transform-origin: top left; +} \ No newline at end of file diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index 11ef6562f..f1f802c13 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -84,8 +84,13 @@ export class EquationBox extends ViewBoxBaseComponent !e.ctrlKey && e.stopPropagation()} + const scale = (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); + return (
!e.ctrlKey && e.stopPropagation()} style={{ + transform: `scale(${scale})`, + width: `${100 / scale}%`, + height: `${100 / scale}%`, pointerEvents: !this.props.isSelected() ? "none" : undefined, }} onKeyDown={e => e.stopPropagation()} diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 3e5c4456c..ebd509669 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1469,19 +1469,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } tryUpdateScrollHeight = () => { - if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath())) { - const margins = 2 * NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0); - const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined; - if (children) { - 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 - const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight; - if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) { - setScrollHeight(); - } else { - setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived... - } + const margins = 2 * NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0); + const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined; + if (children) { + 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 + const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight; + if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) { + setScrollHeight(); + } else { + setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived... } } } -- cgit v1.2.3-70-g09d2 From e295f6694bed9a3a35a0858c8f17745ef1506f51 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 Sep 2021 12:52:38 -0400 Subject: replaced convert to ink in marquee menu with create Group --- .../collectionFreeForm/MarqueeOptionsMenu.tsx | 38 ++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index 71642216c..1f59f9732 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -3,13 +3,15 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Tooltip } from "@material-ui/core"; import { observer } from "mobx-react"; import { unimplementedFunction } from "../../../../Utils"; +import { DocumentType } from "../../../documents/DocumentTypes"; +import { SelectionManager } from "../../../util/SelectionManager"; import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu"; @observer export class MarqueeOptionsMenu extends AntimodeMenu { static Instance: MarqueeOptionsMenu; - public createCollection: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; + public createCollection: (e: KeyboardEvent | React.PointerEvent | undefined, group?: boolean) => void = unimplementedFunction; public delete: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; public summarize: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; public inkToText: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; @@ -26,42 +28,52 @@ export class MarqueeOptionsMenu extends AntimodeMenu { render() { const presPinWithViewIcon = ; const buttons = [ -
Create a Collection
} placement="bottom"> + Create a Collection
} placement="bottom"> , -
Summarize Documents
} placement="bottom"> + Create a Grouping
} placement="bottom"> , -
Delete Documents
} placement="bottom"> + Summarize Documents
} placement="bottom"> , -
Change to Text
} placement="bottom"> + Delete Documents
} placement="bottom"> , -
Pin with selected region
} placement="bottom"> + Pin with selected region
} placement="bottom"> , ]; + if (false && !SelectionManager.Views().some(v => v.props.Document.type !== DocumentType.INK)) { + buttons.push( + Change to Text
} placement="bottom"> + + ); + } return this.getElement(buttons); } } \ No newline at end of file -- cgit v1.2.3-70-g09d2