aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/DocumentManager.ts5
-rw-r--r--src/client/util/DragManager.ts15
-rw-r--r--src/client/util/InteractionUtils.tsx149
-rw-r--r--src/client/util/LinkManager.ts27
-rw-r--r--src/client/util/UndoManager.ts19
5 files changed, 83 insertions, 132 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index b66befb08..66b6a1e44 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -161,7 +161,8 @@ export class DocumentManager {
originatingDoc: Opt<Doc> = undefined, // doc that initiated the display of the target odoc
finished?: () => void,
originalTarget?: Doc,
- noSelect?: boolean
+ noSelect?: boolean,
+ presZoom?: number
): Promise<void> => {
originalTarget = originalTarget ?? targetDoc;
const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView;
@@ -194,7 +195,7 @@ export class DocumentManager {
if (focusView) {
!noSelect && Doc.linkFollowHighlight(focusView.rootDoc); //TODO:glr make this a setting in PresBox
focusView.focus(targetDoc, {
- originalTarget, willZoom, afterFocus: (didFocus: boolean) =>
+ originalTarget, willZoom, scale: presZoom, afterFocus: (didFocus: boolean) =>
new Promise<ViewAdjustment>(res => {
focusAndFinish(didFocus);
res();
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 421e4c6bb..f5704d2bf 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -365,6 +365,21 @@ export namespace DragManager {
const dragElements = eles.map(ele => {
if (!ele.parentNode) dragDiv.appendChild(ele);
const dragElement = ele.parentNode === dragDiv ? ele : ele.cloneNode(true) as HTMLElement;
+ const children = Array.from(dragElement.children);
+ while (children.length) { // need to replace all the maker node reference ids with new unique ids. otherwise, the clone nodes will reference the original nodes which are all hidden during the drag
+ const next = children.pop();
+ next && children.push(...Array.from(next.children));
+ if (next) {
+ ["marker-start", "marker-mid", "marker-end"].forEach(field => {
+ if (next.localName.startsWith("path") && (next.attributes as any)[field]) {
+ next.setAttribute(field, (next.attributes as any)[field].value.replace("#", "#X"));
+ }
+ });
+ if (next.localName.startsWith("marker")) {
+ next.id = "X" + next.id;
+ }
+ }
+ }
const rect = ele.getBoundingClientRect();
const scaleX = rect.width / ele.offsetWidth;
const scaleY = ele.offsetHeight ? rect.height / ele.offsetHeight : scaleX;
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 4a8011e3c..a32a8eecc 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -1,10 +1,6 @@
import React = require("react");
-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";
+import "./InteractionUtils.scss";
export namespace InteractionUtils {
export const MOUSETYPE = "mouse";
@@ -93,122 +89,43 @@ export namespace InteractionUtils {
return myTouches;
}
- export function CreatePoints(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, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean, nodefs: boolean) {
- let pts: { X: number; Y: number; }[] = [];
- if (shape) { //if any of the shape are true
- pts = makePolygon(shape, points);
- }
- else if ((points.length >= 5 && points[3].X === points[4].X) || (points.length === 4)) {
- for (var i = 0; i < points.length - 3; i += 4) {
- const array = [[points[i].X, points[i].Y], [points[i + 1].X, points[i + 1].Y], [points[i + 2].X, points[i + 2].Y], [points[i + 3].X, points[i + 3].Y]];
- for (var t = 0; t < 1; t += 0.01) {
- const point = beziercurve(t, array);
- pts.push({ X: point[0], Y: point[1] });
- }
- }
- }
- else if (points.length > 1 && points[points.length - 1].X === points[0].X && points[points.length - 1].Y === points[0].Y) {
- //pointer is up (first and last points are the same)
- const newPoints = points.reduce((p, pts) => { p.push([pts.X, pts.Y]); return p; }, [] as number[][]);
- newPoints.pop();
-
- const bezierCurves = fitCurve(newPoints, parseInt(bezier));
- for (const curve of bezierCurves) {
- for (var t = 0; t < 1; t += 0.01) {
- const point = beziercurve(t, curve);
- pts.push({ X: point[0], Y: point[1] });
- }
- }
- } else {
- pts = points.slice();
- // bcz: Ugh... this is ugly, but shapes apprently have an extra point added that is = (p[0].x,p[0].y+1) as some sort of flag. need to remove it here.
- if (pts.length > 2 && pts[pts.length - 2].X === pts[0].X && pts[pts.length - 2].Y === pts[0].Y) {
- pts.pop();
- }
- }
- if (isNaN(scalex)) {
- scalex = 1;
- }
- if (isNaN(scaley)) {
- scaley = 1;
- }
- return pts;
- }
+ export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number,
+ color: string, width: number, strokeWidth: number, lineJoin: string, lineCap: string, bezier: string, fill: string, arrowStart: string, arrowEnd: string,
+ dash: string | undefined, scalex: number, scaley: number, shape: string, pevents: string, opacity: number, nodefs: boolean) {
+ const pts = shape ? makePolygon(shape, points) : points;
+ if (isNaN(scalex)) scalex = 1;
+ if (isNaN(scaley)) scaley = 1;
+ const toScr = (p: { X: number, Y: number }) => ` ${!p ? 0 : (p.X - left - width / 2) * scalex + width / 2}, ${!p ? 0 : (p.Y - top - width / 2) * scaley + width / 2} `;
+ const strpts = bezier ?
+ pts.reduce((acc: string, pt, i) => acc + (i % 4 !== 0 ? "" : (i === 0 ? "M" + toScr(pt) : "") + "C" + toScr(pts[i + 1]) + toScr(pts[i + 2]) + toScr(pts[i + 3])), "") :
+ pts.reduce((acc: string, pt) => acc + `${toScr(pt)} `, "");
- 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, opacity: number, nodefs: boolean) {
- let pts: { X: number; Y: number; }[] = [];
- if (shape) { //if any of the shape are true
- pts = makePolygon(shape, points);
- }
- else if ((points.length >= 5 && points[3].X === points[4].X) || (points.length === 4)) {
- for (var i = 0; i < points.length - 3; i += 4) {
- const array = [[points[i].X, points[i].Y], [points[i + 1].X, points[i + 1].Y], [points[i + 2].X, points[i + 2].Y], [points[i + 3].X, points[i + 3].Y]];
- for (var t = 0; t < 1; t += 0.01) {
- const point = beziercurve(t, array);
- pts.push({ X: point[0], Y: point[1] });
- }
- }
- }
- else if (points.length > 1 && points[points.length - 1].X === points[0].X && points[points.length - 1].Y === points[0].Y) {
- //pointer is up (first and last points are the same)
- const newPoints = points.reduce((p, pts) => { p.push([pts.X, pts.Y]); return p; }, [] as number[][]);
- newPoints.pop();
-
- const bezierCurves = fitCurve(newPoints, parseInt(bezier));
- for (const curve of bezierCurves) {
- for (var t = 0; t < 1; t += 0.01) {
- const point = beziercurve(t, curve);
- pts.push({ X: point[0], Y: point[1] });
- }
- }
- } else {
- pts = points.slice();
- // bcz: Ugh... this is ugly, but shapes apprently have an extra point added that is = (p[0].x,p[0].y+1) as some sort of flag. need to remove it here.
- if (pts.length > 2 && pts[pts.length - 2].X === pts[0].X && pts[pts.length - 2].Y === pts[0].Y) {
- pts.pop();
- }
- }
- if (isNaN(scalex)) {
- scalex = 1;
- }
- if (isNaN(scaley)) {
- scaley = 1;
- }
- const strpts = pts.reduce((acc: string, pt: { X: number, Y: number }) => acc +
- `${(pt.X - left - width / 2) * scalex + width / 2},
- ${(pt.Y - top - width / 2) * scaley + width / 2} `, "");
const dashArray = dash && Number(dash) ? String(Number(width) * Number(dash)) : undefined;
const defGuid = Utils.GenerateGuid();
- const arrowDim = Math.max(0.5, 8 / Math.log(Math.max(2, strokeWidth)));
-
- const addables = pts.map((pts, i) =>
- <svg height="10" width="10">
- <circle cx={(pts.X - left - width / 2) * scalex + width / 2} cy={(pts.Y - top - width / 2) * scaley + width / 2} r={strokeWidth / 2} stroke="black" strokeWidth={1} fill="blue"
- onDoubleClick={(e) => { console.log(i); }} pointerEvents="all" cursor="all-scroll"
- />
- </svg>);
-
+ const Tag = (bezier ? "path" : "polyline") as keyof JSX.IntrinsicElements;
+ const makerStrokeWidth = strokeWidth / 2;
return (<svg fill={color}> {/* setting the svg fill sets the arrowStart fill */}
{nodefs ? (null) : <defs>
- {arrowStart !== "dot" && arrowEnd !== "dot" ? (null) : <marker id={`dot${defGuid}`} orient="auto" overflow="visible">
- <circle r={1} fill="context-stroke" />
- </marker>}
- {arrowStart !== "arrow" && arrowEnd !== "arrow" ? (null) : <marker id={`arrowStart${defGuid}`} orient="auto" overflow="visible" refX="1.6" refY="0" markerWidth="10" markerHeight="7">
- <polygon points={`${arrowDim} ${-Math.max(1, arrowDim / 2)}, ${arrowDim} ${Math.max(1, arrowDim / 2)}, -1 0`} />
- </marker>}
- {arrowStart !== "arrow" && arrowEnd !== "arrow" ? (null) : <marker id={`arrowEnd${defGuid}`} orient="auto" overflow="visible" refX="1.6" refY="0" markerWidth="10" markerHeight="7">
- <polygon points={`${2 - arrowDim} ${-Math.max(1, arrowDim / 2)}, ${2 - arrowDim} ${Math.max(1, arrowDim / 2)}, 3 0`} />
- </marker>}
+ {arrowStart !== "dot" && arrowEnd !== "dot" ? (null) :
+ <marker id={`dot${defGuid}`} orient="auto" markerUnits="userSpaceOnUse" refX={0} refY="0" overflow="visible">
+ <circle r={strokeWidth * 1.5} fill="context-stroke" />
+ </marker>}
+ {arrowStart !== "arrow" ? (null) :
+ <marker id={`arrowStart${defGuid}`} markerUnits="userSpaceOnUse" orient="auto" overflow="visible" refX={makerStrokeWidth * 1.5} refY={0} markerWidth="10" markerHeight="7">
+ <polygon style={{ stroke: color }} strokeLinejoin={lineJoin as any} strokeWidth={makerStrokeWidth * 2 / 3} points={`${3 * makerStrokeWidth} ${-makerStrokeWidth * 1.5}, ${makerStrokeWidth * 2} 0, ${3 * makerStrokeWidth} ${makerStrokeWidth * 1.5}, 0 0`} />
+ </marker>}
+ {arrowEnd !== "arrow" ? (null) :
+ <marker id={`arrowEnd${defGuid}`} markerUnits="userSpaceOnUse" orient="auto" overflow="visible" refX={makerStrokeWidth * 1.5} refY={0} markerWidth="10" markerHeight="7">
+ <polygon style={{ stroke: color }} strokeLinejoin={lineJoin as any} strokeWidth={makerStrokeWidth * 2 / 3} points={`0 ${-makerStrokeWidth * 1.5}, ${makerStrokeWidth} 0, 0 ${makerStrokeWidth * 1.5}, ${3 * makerStrokeWidth} 0`} />
+ </marker>}
</defs>}
- <polyline
- points={strpts}
+
+ <Tag
+ d={bezier ? strpts : undefined}
+ points={bezier ? undefined : strpts}
style={{
// filter: drawHalo ? "url(#inkSelectionHalo)" : undefined,
fill: fill && fill !== "transparent" ? fill : "none",
@@ -217,14 +134,12 @@ export namespace InteractionUtils {
pointerEvents: pevents as any,
stroke: color ?? "rgb(0, 0, 0)",
strokeWidth: strokeWidth,
- strokeLinejoin: color === "rgba(245, 230, 95, 0.75)" ? "miter" : "round",
- strokeLinecap: color === "rgba(245, 230, 95, 0.75)" ? "square" : "round",
+ strokeLinecap: lineCap as any,
strokeDasharray: dashArray
}}
- markerStart={`url(#${arrowStart + "Start" + defGuid})`}
- markerEnd={`url(#${arrowEnd + "End" + defGuid})`}
+ markerStart={`url(#${arrowStart === "dot" ? arrowStart + defGuid : arrowStart + "Start" + defGuid})`}
+ markerEnd={`url(#${arrowEnd === "dot" ? arrowEnd + defGuid : arrowEnd + "End" + defGuid})`}
/>
- {/* {addables} */}
</svg>);
}
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 64da68f59..90a8f2737 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -38,15 +38,19 @@ export class LinkManager {
const addLinkToDoc = (link: Doc) => {
const a1Prom = link?.anchor1;
const a2Prom = link?.anchor2;
- Promise.all([a1Prom, a2Prom]).then(action((all) => {
+ Promise.all([a1Prom, a2Prom]).then((all) => {
const a1 = all[0];
const a2 = all[1];
- if (a1 instanceof Doc && a2 instanceof Doc && ((a1.author !== undefined && a2.author !== undefined) || link.author === Doc.CurrentUserEmail)) {
- Doc.GetProto(a1)[DirectLinksSym].add(link);
- Doc.GetProto(a2)[DirectLinksSym].add(link);
- Doc.GetProto(link)[DirectLinksSym].add(link);
- }
- }));
+ const a1ProtoProm = (link?.anchor1 as Doc)?.proto;
+ const a2ProtoProm = (link?.anchor2 as Doc)?.proto;
+ Promise.all([a1ProtoProm, a2ProtoProm]).then(action((all) => {
+ if (a1 instanceof Doc && a2 instanceof Doc && ((a1.author !== undefined && a2.author !== undefined) || link.author === Doc.CurrentUserEmail)) {
+ Doc.GetProto(a1)[DirectLinksSym].add(link);
+ Doc.GetProto(a2)[DirectLinksSym].add(link);
+ Doc.GetProto(link)[DirectLinksSym].add(link);
+ }
+ }));
+ });
};
const remLinkFromDoc = (link: Doc) => {
const a1 = link?.anchor1;
@@ -100,12 +104,9 @@ export class LinkManager {
public createLinkrelationshipLists = () => {
//create new lists for link relations and their associated colors if the lists don't already exist
- if (!Doc.UserDoc().linkRelationshipList && !Doc.UserDoc().linkColorList) {
- const linkRelationshipList = new List<string>();
- const linkColorList = new List<string>();
- Doc.UserDoc().linkRelationshipList = linkRelationshipList;
- Doc.UserDoc().linkColorList = linkColorList;
- }
+ !Doc.UserDoc().linkRelationshipList && (Doc.UserDoc().linkRelationshipList = new List<string>());
+ !Doc.UserDoc().linkColorList && (Doc.UserDoc().linkColorList = new List<string>());
+ !Doc.UserDoc().linkRelationshipSizes && (Doc.UserDoc().linkRelationshipSizes = new List<number>());
}
public addLink(linkDoc: Doc, checkExists = false) {
diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts
index 05fb9f378..44e44d335 100644
--- a/src/client/util/UndoManager.ts
+++ b/src/client/util/UndoManager.ts
@@ -70,6 +70,7 @@ export namespace UndoManager {
export interface UndoEvent {
undo: () => void;
redo: () => void;
+ prop: string;
}
type UndoBatch = UndoEvent[];
@@ -104,6 +105,23 @@ export namespace UndoManager {
export function GetOpenBatches(): Without<Batch, 'end'>[] {
return openBatches;
}
+ export function FilterBatches(fieldTypes: string[]) {
+ const fieldCounts: { [key: string]: number } = {};
+ const lastStack = UndoManager.undoStack.lastElement();
+ if (lastStack) {
+ lastStack.forEach(ev => fieldTypes.includes(ev.prop) && (fieldCounts[ev.prop] = (fieldCounts[ev.prop] || 0) + 1));
+ const fieldCount2: { [key: string]: number } = {};
+ runInAction(() =>
+ UndoManager.undoStack[UndoManager.undoStack.length - 1] = lastStack.filter(ev => {
+ if (fieldTypes.includes(ev.prop)) {
+ fieldCount2[ev.prop] = (fieldCount2[ev.prop] || 0) + 1;
+ if (fieldCount2[ev.prop] === 1 || fieldCount2[ev.prop] === fieldCounts[ev.prop]) return true;
+ return false;
+ }
+ return true;
+ }));
+ }
+ }
export function TraceOpenBatches() {
console.log(`Open batches:\n\t${openBatches.map(batch => batch.batchName).join("\n\t")}\n`);
}
@@ -140,6 +158,7 @@ export namespace UndoManager {
batchCounter--;
// console.log("End " + batchCounter);
if (batchCounter === 0 && currentBatch?.length) {
+ // console.log("------ended----")
if (!cancel) {
undoStack.push(currentBatch);
}