aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/DocumentManager.ts2
-rw-r--r--src/client/util/DragManager.ts205
-rw-r--r--src/client/util/DropConverter.ts4
-rw-r--r--src/client/util/Scripting.ts2
-rw-r--r--src/client/util/SelectionManager.ts6
-rw-r--r--src/client/util/SettingsManager.tsx5
-rw-r--r--src/client/util/SnappingManager.ts29
7 files changed, 135 insertions, 118 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 4683e77a8..1ba6f0248 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -117,7 +117,7 @@ export class DocumentManager {
pairs.push(...linksList.reduce((pairs, link) => {
const linkToDoc = link && LinkManager.Instance.getOppositeAnchor(link, dv.props.Document);
linkToDoc && DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => {
- if (dv.props.Document.type !== DocumentType.LINK || dv.props.layoutKey !== docView1.props.layoutKey) {
+ if (dv.props.Document.type !== DocumentType.LINK || dv.props.LayoutTemplateString !== docView1.props.LayoutTemplateString) {
pairs.push({ a: dv, b: docView1, l: link });
}
});
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index a905dff0a..d1d7f2a8a 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -1,25 +1,17 @@
-import { Doc, Field, DocListCast } from "../../new_fields/Doc";
-import { Cast, ScriptCast, StrCast } from "../../new_fields/Types";
-import { emptyFunction } from "../../Utils";
-import { CollectionDockingView } from "../views/collections/CollectionDockingView";
-import * as globalCssVariables from "../views/globalCssVariables.scss";
-import { DocumentManager } from "./DocumentManager";
-import { LinkManager } from "./LinkManager";
-import { SelectionManager } from "./SelectionManager";
-import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
-import { Docs, DocUtils } from "../documents/Documents";
-import { ScriptField } from "../../new_fields/ScriptField";
+import { action, observable, runInAction } from "mobx";
+import { DateField } from "../../new_fields/DateField";
+import { Doc, Field, Opt } from "../../new_fields/Doc";
import { List } from "../../new_fields/List";
import { PrefetchProxy } from "../../new_fields/Proxy";
import { listSpec } from "../../new_fields/Schema";
-import { Scripting } from "./Scripting";
-import { convertDropDataToButtons } from "./DropConverter";
-import { AudioBox } from "../views/nodes/AudioBox";
-import { DateField } from "../../new_fields/DateField";
-import { DocumentView } from "../views/nodes/DocumentView";
+import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
+import { ScriptField } from "../../new_fields/ScriptField";
+import { Cast, NumCast, ScriptCast, StrCast } from "../../new_fields/Types";
+import { emptyFunction } from "../../Utils";
+import { Docs, DocUtils } from "../documents/Documents";
+import * as globalCssVariables from "../views/globalCssVariables.scss";
import { UndoManager } from "./UndoManager";
-import { PointData } from "../../new_fields/InkField";
-import { MainView } from "../views/MainView";
+import { SnappingManager } from "./SnappingManager";
export type dropActionType = "alias" | "copy" | "move" | undefined; // undefined = move
export function SetupDrag(
@@ -55,10 +47,10 @@ export function SetupDrag(
const onItemDown = async (e: React.PointerEvent) => {
if (e.button === 0) {
e.stopPropagation();
- if (e.shiftKey && CollectionDockingView.Instance) {
+ if (e.shiftKey) {
e.persist();
const dragDoc = await docFunc();
- dragDoc && CollectionDockingView.Instance.StartOtherDrag({
+ dragDoc && DragManager.StartWindowDrag?.({
pageX: e.pageX,
pageY: e.pageY,
preventDefault: emptyFunction,
@@ -75,8 +67,7 @@ export function SetupDrag(
export namespace DragManager {
let dragDiv: HTMLDivElement;
- export let horizSnapLines: number[];
- export let vertSnapLines: number[];
+ export let StartWindowDrag: Opt<((e: any, dragDocs: Doc[]) => void)> = undefined;
export function Root() {
const root = document.getElementById("root");
@@ -86,8 +77,8 @@ export namespace DragManager {
return root;
}
export let AbortDrag: () => void = emptyFunction;
- export type MoveFunction = (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
- export type RemoveFunction = (document: Doc) => boolean;
+ export type MoveFunction = (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
+ export type RemoveFunction = (document: Doc | Doc[]) => boolean;
export interface DragDropDisposer { (): void; }
export interface DragOptions {
@@ -184,7 +175,8 @@ export namespace DragManager {
export function MakeDropTarget(
element: HTMLElement,
dropFunc: (e: Event, de: DropEvent) => void,
- doc?: Doc
+ doc?: Doc,
+ preDropFunc?: (e: Event, de: DropEvent, targetAction: dropActionType) => void,
): DragDropDisposer {
if ("canDrop" in element.dataset) {
throw new Error(
@@ -195,9 +187,7 @@ export namespace DragManager {
const handler = (e: Event) => dropFunc(e, (e as CustomEvent<DropEvent>).detail);
const preDropHandler = (e: Event) => {
const de = (e as CustomEvent<DropEvent>).detail;
- if (de.complete.docDragData && doc?.targetDropAction) {
- de.complete.docDragData.dropAction = StrCast(doc.targetDropAction) as dropActionType;
- }
+ preDropFunc?.(e, de, StrCast(doc?.targetDropAction) as dropActionType);
};
element.addEventListener("dashOnDrop", handler);
doc && element.addEventListener("dashPreDrop", preDropHandler);
@@ -212,7 +202,7 @@ export namespace DragManager {
export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) {
const addAudioTag = (dropDoc: any) => {
dropDoc && !dropDoc.creationDate && (dropDoc.creationDate = new DateField);
- dropDoc instanceof Doc && AudioBox.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: dropDoc }, { doc: d }, "audio link", "audio timeline"));
+ dropDoc instanceof Doc && DocUtils.MakeLinkToActiveAudio(dropDoc);
return dropDoc;
};
const batch = UndoManager.StartBatch("dragging");
@@ -243,40 +233,6 @@ export namespace DragManager {
StartDrag(eles, new DragManager.DocumentDragData([]), downX, downY, options, finishDrag);
}
- // drag links and drop link targets (aliasing them if needed)
- export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: DocumentView, downX: number, downY: number, sourceDoc: Doc, specificLinks?: Doc[]) {
- const draggedDocs = (specificLinks ? specificLinks : DocListCast(sourceDoc.links)).map(link => LinkManager.Instance.getOppositeAnchor(link, sourceDoc)).filter(l => l) as Doc[];
-
- if (draggedDocs.length) {
- const moddrag: Doc[] = [];
- for (const draggedDoc of draggedDocs) {
- const doc = await Cast(draggedDoc.annotationOn, Doc);
- if (doc) moddrag.push(doc);
- }
-
- const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs);
- dragData.moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean => {
- docView.props.removeDocument?.(doc);
- addDocument(doc);
- return true;
- };
- const containingView = docView.props.ContainingCollectionView;
- const finishDrag = (e: DragCompleteEvent) =>
- e.docDragData && (e.docDragData.droppedDocuments =
- dragData.draggedDocuments.reduce((droppedDocs, d) => {
- const dvs = DocumentManager.Instance.getDocumentViews(d).filter(dv => dv.props.ContainingCollectionView === containingView);
- if (dvs.length) {
- dvs.forEach(dv => droppedDocs.push(dv.props.Document));
- } else {
- droppedDocs.push(Doc.MakeAlias(d));
- }
- return droppedDocs;
- }, [] as Doc[]));
-
- StartDrag([dragEle], dragData, downX, downY, undefined, finishDrag);
- }
- }
-
// drag&drop the pdf annotation anchor which will create a text note on drop via a dropCompleted() DragOption
export function StartPdfAnnoDrag(eles: HTMLElement[], dragData: PdfAnnoDragData, downX: number, downY: number, options?: DragOptions) {
StartDrag(eles, dragData, downX, downY, options);
@@ -296,15 +252,64 @@ export namespace DragManager {
StartDrag([ele], {}, downX, downY);
}
- @action
export function SetSnapLines(horizLines: number[], vertLines: number[]) {
- horizSnapLines = horizLines;
- vertSnapLines = vertLines;
- MainView.Instance._hLines = horizLines;
- MainView.Instance._vLines = vertLines;
+ SnappingManager.setSnapLines(horizLines, vertLines);
}
+ export function snapDragAspect(dragPt: number[], snapAspect: number) {
+ let closest = NumCast(Doc.UserDoc()["constants-snapThreshold"], 10);
+ let near = dragPt;
+ const intersect = (x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, dragx: number, dragy: number) => {
+ if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) return undefined; // Check if none of the lines are of length 0
+ const denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1));
+ if (denominator === 0) return undefined; // Lines are parallel
+
+ let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
+ // let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;
+ //if (ua < 0 || ua > 1 || ub < 0 || ub > 1) return undefined; // is the intersection along the segments
- function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) {
+ // Return a object with the x and y coordinates of the intersection
+ let x = x1 + ua * (x2 - x1)
+ let y = y1 + ua * (y2 - y1)
+ const dist = Math.sqrt((dragx - x) * (dragx - x) + (dragy - y) * (dragy - y));
+ return { pt: [x, y], dist }
+ }
+ SnappingManager.vertSnapLines().forEach((xCoord, i) => {
+ const pt = intersect(dragPt[0], dragPt[1], dragPt[0] + snapAspect, dragPt[1] + 1, xCoord, -1, xCoord, 1, dragPt[0], dragPt[1]);
+ if (pt && pt.dist < closest) {
+ closest = pt.dist;
+ near = pt.pt;
+ }
+ });
+ SnappingManager.horizSnapLines().forEach((yCoord, i) => {
+ const pt = intersect(dragPt[0], dragPt[1], dragPt[0] + snapAspect, dragPt[1] + 1, -1, yCoord, 1, yCoord, dragPt[0], dragPt[1]);
+ if (pt && pt.dist < closest) {
+ closest = pt.dist;
+ near = pt.pt;
+ }
+ });
+ return { thisX: near[0], thisY: near[1] };
+ }
+ // snap to the active snap lines - if oneAxis is set (eg, for maintaining aspect ratios), then it only snaps to the nearest horizontal/vertical line
+ export function snapDrag(e: PointerEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number) {
+ const snapThreshold = NumCast(Doc.UserDoc()["constants-snapThreshold"], 10);
+ const snapVal = (pts: number[], drag: number, snapLines: number[]) => {
+ if (snapLines.length) {
+ const offs = [pts[0], (pts[0] - pts[1]) / 2, -pts[1]]; // offsets from drag pt
+ const rangePts = [drag - offs[0], drag - offs[1], drag - offs[2]]; // left, mid, right or top, mid, bottom pts to try to snap to snaplines
+ const closestPts = rangePts.map(pt => snapLines.reduce((nearest, curr) => Math.abs(nearest - pt) > Math.abs(curr - pt) ? curr : nearest));
+ const closestDists = rangePts.map((pt, i) => Math.abs(pt - closestPts[i]));
+ const minIndex = closestDists[0] < closestDists[1] && closestDists[0] < closestDists[2] ? 0 : closestDists[1] < closestDists[2] ? 1 : 2;
+ return closestDists[minIndex] < snapThreshold ? closestPts[minIndex] + offs[minIndex] : drag;
+ }
+ return drag;
+ };
+ return {
+ thisX: snapVal([xFromLeft, xFromRight], e.pageX, SnappingManager.vertSnapLines()),
+ thisY: snapVal([yFromTop, yFromBottom], e.pageY, SnappingManager.horizSnapLines())
+ };
+ }
+ export let docsBeingDragged: Doc[] = [];
+ export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) {
eles = eles.filter(e => e);
if (!dragDiv) {
dragDiv = document.createElement("div");
@@ -312,13 +317,13 @@ export namespace DragManager {
dragDiv.style.pointerEvents = "none";
DragManager.Root().appendChild(dragDiv);
}
- SelectionManager.SetIsDragging(true);
+ SnappingManager.SetIsDragging(true);
const scaleXs: number[] = [];
const scaleYs: number[] = [];
const xs: number[] = [];
const ys: number[] = [];
- const docs = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof PdfAnnoDragData ? [dragData.dragDocument] : [];
+ docsBeingDragged = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof PdfAnnoDragData ? [dragData.dragDocument] : [];
const elesCont = {
left: Number.MAX_SAFE_INTEGER,
top: Number.MAX_SAFE_INTEGER,
@@ -354,7 +359,7 @@ export namespace DragManager {
dragElement.style.width = `${rect.width / scaleX}px`;
dragElement.style.height = `${rect.height / scaleY}px`;
- if (docs.length) {
+ if (docsBeingDragged.length) {
const pdfBox = dragElement.getElementsByTagName("canvas");
const pdfBoxSrc = ele.getElementsByTagName("canvas");
Array.from(pdfBox).map((pb, i) => pb.getContext('2d')!.drawImage(pdfBoxSrc[i], 0, 0));
@@ -394,46 +399,22 @@ export namespace DragManager {
if (dragData instanceof DocumentDragData) {
dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : undefined;
}
- if (e.shiftKey && CollectionDockingView.Instance && dragData.droppedDocuments.length === 1) {
+ if (e.shiftKey && dragData.droppedDocuments.length === 1) {
!dragData.dropAction && (dragData.dropAction = alias);
if (dragData.dropAction === "move") {
dragData.removeDocument?.(dragData.draggedDocuments[0]);
}
AbortDrag();
finishDrag?.(new DragCompleteEvent(true, dragData));
- CollectionDockingView.Instance.StartOtherDrag({
+ DragManager.StartWindowDrag?.({
pageX: e.pageX,
pageY: e.pageY,
preventDefault: emptyFunction,
button: 0
}, dragData.droppedDocuments);
}
- let thisX = e.pageX;
- let thisY = e.pageY;
- const currLeft = e.pageX - xFromLeft;
- const currTop = e.pageY - yFromTop;
- const currRight = e.pageX + xFromRight;
- const currBottom = e.pageY + yFromBottom;
- const closestLeft = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currLeft) > Math.abs(curr - currLeft) ? curr : prev);
- const closestTop = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currTop) > Math.abs(curr - currTop) ? curr : prev);
- const closestRight = vertSnapLines.reduce((prev, curr) => Math.abs(prev - currRight) > Math.abs(curr - currRight) ? curr : prev);
- const closestBottom = horizSnapLines.reduce((prev, curr) => Math.abs(prev - currBottom) > Math.abs(curr - currBottom) ? curr : prev);
- const distFromClosestLeft = Math.abs(e.pageX - xFromLeft - closestLeft);
- const distFromClosestTop = Math.abs(e.pageY - yFromTop - closestTop);
- const distFromClosestRight = Math.abs(e.pageX + xFromRight - closestRight);
- const distFromClosestBottom = Math.abs(e.pageY + yFromBottom - closestBottom);
- if (distFromClosestLeft < 10 && distFromClosestLeft < distFromClosestRight) {
- thisX = closestLeft + xFromLeft;
- }
- else if (distFromClosestRight < 10) {
- thisX = closestRight - xFromRight;
- }
- if (distFromClosestTop < 10 && distFromClosestTop < distFromClosestRight) {
- thisY = closestTop + yFromTop;
- }
- else if (distFromClosestBottom < 10) {
- thisY = closestBottom - yFromBottom;
- }
+
+ const { thisX, thisY } = snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom);
alias = "move";
const moveX = thisX - lastX;
@@ -449,21 +430,22 @@ export namespace DragManager {
dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement));
eles.map(ele => ele.parentElement && ele.parentElement?.className === dragData.dragDivName ? (ele.parentElement.hidden = false) : (ele.hidden = false));
};
- const endDrag = () => {
+ const endDrag = action(() => {
document.removeEventListener("pointermove", moveHandler, true);
document.removeEventListener("pointerup", upHandler);
- };
+ SnappingManager.clearSnapLines();
+ });
AbortDrag = () => {
hideDragShowOriginalElements();
- SelectionManager.SetIsDragging(false);
+ SnappingManager.SetIsDragging(false);
options?.dragComplete?.(new DragCompleteEvent(true, dragData));
endDrag();
};
const upHandler = (e: PointerEvent) => {
hideDragShowOriginalElements();
- dispatchDrag(eles, e, dragData, options, finishDrag);
- SelectionManager.SetIsDragging(false);
+ dispatchDrag(eles, e, dragData, xFromLeft, yFromTop, xFromRight, yFromBottom, options, finishDrag);
+ SnappingManager.SetIsDragging(false);
endDrag();
options?.dragComplete?.(new DragCompleteEvent(false, dragData));
};
@@ -471,7 +453,8 @@ export namespace DragManager {
document.addEventListener("pointerup", upHandler);
}
- function dispatchDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (e: DragCompleteEvent) => void) {
+ function dispatchDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any },
+ xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number, options?: DragOptions, finishDrag?: (e: DragCompleteEvent) => void) {
const removed = dragData.dontHideOnDrop ? [] : dragEles.map(dragEle => {
const ret = { ele: dragEle, w: dragEle.style.width, h: dragEle.style.height, o: dragEle.style.overflow };
dragEle.style.width = "0";
@@ -485,14 +468,15 @@ export namespace DragManager {
r.ele.style.height = r.h;
r.ele.style.overflow = r.o;
});
+ const { thisX, thisY } = snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom);
if (target) {
const complete = new DragCompleteEvent(false, dragData);
target.dispatchEvent(
new CustomEvent<DropEvent>("dashPreDrop", {
bubbles: true,
detail: {
- x: e.x,
- y: e.y,
+ x: thisX,
+ y: thisY,
complete: complete,
shiftKey: e.shiftKey,
altKey: e.altKey,
@@ -506,8 +490,8 @@ export namespace DragManager {
new CustomEvent<DropEvent>("dashOnDrop", {
bubbles: true,
detail: {
- x: e.x,
- y: e.y,
+ x: thisX,
+ y: thisY,
complete: complete,
shiftKey: e.shiftKey,
altKey: e.altKey,
@@ -519,4 +503,3 @@ export namespace DragManager {
}
}
}
-Scripting.addGlobal(function convertToButtons(dragData: any) { convertDropDataToButtons(dragData as DragManager.DocumentDragData); });
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index 60a6bbb3c..d6db882b8 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -7,6 +7,7 @@ import { Docs } from "../documents/Documents";
import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
import { RichTextField } from "../../new_fields/RichTextField";
import { ImageField } from "../../new_fields/URLField";
+import { Scripting } from "./Scripting";
//
// converts 'doc' into a template that can be used to render other documents.
@@ -68,10 +69,11 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
});
dbox.dragFactory = layoutDoc;
dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined;
- dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)');
+ dbox.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory)');
} else if (doc.isButtonBar) {
dbox.ignoreClick = true;
}
data.droppedDocuments[i] = dbox;
});
}
+Scripting.addGlobal(function convertToButtons(dragData: any) { convertDropDataToButtons(dragData as DragManager.DocumentDragData); }); \ No newline at end of file
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index 12628273b..8b7b9c9c7 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -136,7 +136,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an
if (batch) {
batch.end();
}
- onError && onError(error);
+ onError?.(error);
return { success: false, error, result: errorVal };
}
};
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index a49977c42..11d2cafb2 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -11,7 +11,6 @@ export namespace SelectionManager {
@observable IsDragging: boolean = false;
SelectedDocuments: ObservableMap<DocumentView, boolean> = new ObservableMap();
-
@action
SelectDoc(docView: DocumentView, ctrlPressed: boolean): void {
// if doc is not in SelectedDocuments, add it
@@ -55,6 +54,8 @@ export namespace SelectionManager {
manager.SelectDoc(docView, ctrlPressed);
}
+ export function SetIsDragging(dragging: boolean) { runInAction(() => manager.IsDragging = dragging); }
+ export function GetIsDragging() { return manager.IsDragging; }
// computed functions, such as used in IsSelected generate errors if they're called outside of a
// reaction context. Specifying the context with 'outsideReaction' allows an efficiency feature
// to avoid unnecessary mobx invalidations when running inside a reaction.
@@ -78,9 +79,6 @@ export namespace SelectionManager {
if (found) manager.SelectDoc(found, false);
}
- export function SetIsDragging(dragging: boolean) { runInAction(() => manager.IsDragging = dragging); }
- export function GetIsDragging() { return manager.IsDragging; }
-
export function SelectedDocuments(): Array<DocumentView> {
return Array.from(manager.SelectedDocuments.keys());
}
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index ff0b22381..e20434461 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -8,6 +8,8 @@ import { SelectionManager } from "./SelectionManager";
import "./SettingsManager.scss";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Networking } from "../Network";
+import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { Utils } from "../../Utils";
library.add(fa.faWindowClose);
@@ -90,6 +92,9 @@ export default class SettingsManager extends React.Component<{}> {
<div className="settings-type">
<button onClick={this.onClick} value="password">reset password</button>
<button onClick={this.onClick} value="data">reset data</button>
+ <button onClick={() => window.location.assign(Utils.prepend("/logout"))}>
+ {CurrentUserUtils.GuestWorkspace ? "Exit" : "Log Out"}
+ </button>
</div>
{this.settingsContent === "password" ?
<div className="settings-content">
diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts
new file mode 100644
index 000000000..fc07e8ab4
--- /dev/null
+++ b/src/client/util/SnappingManager.ts
@@ -0,0 +1,29 @@
+import { observable, action, runInAction } from "mobx";
+
+export namespace SnappingManager {
+
+ class Manager {
+ @observable IsDragging: boolean = false;
+ @observable public horizSnapLines: number[] = [];
+ @observable public vertSnapLines: number[] = [];
+ @action public clearSnapLines() {
+ this.vertSnapLines = [];
+ this.horizSnapLines = [];
+ }
+ @action public setSnapLines(horizLines: number[], vertLines: number[]) {
+ this.horizSnapLines = horizLines;
+ this.vertSnapLines = vertLines;
+ }
+ }
+
+ const manager = new Manager();
+
+ export function clearSnapLines() { manager.clearSnapLines(); }
+ export function setSnapLines(horizLines: number[], vertLines: number[]) { manager.setSnapLines(horizLines, vertLines); }
+ export function horizSnapLines() { return manager.horizSnapLines; }
+ export function vertSnapLines() { return manager.vertSnapLines; }
+
+ export function SetIsDragging(dragging: boolean) { runInAction(() => manager.IsDragging = dragging); }
+ export function GetIsDragging() { return manager.IsDragging; }
+}
+