aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/northstar/dash-nodes/HistogramBox.scss5
-rw-r--r--src/client/util/DragManager.ts533
-rw-r--r--src/client/util/SelectionManager.ts74
-rw-r--r--src/client/views/DocumentDecorations.scss61
-rw-r--r--src/client/views/DocumentDecorations.tsx81
-rw-r--r--src/client/views/InkingCanvas.scss2
-rw-r--r--src/client/views/Main.scss7
-rw-r--r--src/client/views/collections/CollectionDockingView.scss2
-rw-r--r--src/client/views/collections/CollectionPDFView.scss2
-rw-r--r--src/client/views/collections/CollectionVideoView.scss2
-rw-r--r--src/client/views/collections/CollectionViewBase.tsx20
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx8
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx13
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.scss2
-rw-r--r--src/client/views/collections/collectionFreeForm/PreviewCursor.scss4
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.scss2
-rw-r--r--src/client/views/nodes/PDFBox.scss4
-rw-r--r--src/client/views/nodes/WebBox.scss2
-rw-r--r--src/fields/Document.ts773
22 files changed, 882 insertions, 727 deletions
diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss
index b11840a65..94da36e29 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.scss
+++ b/src/client/northstar/dash-nodes/HistogramBox.scss
@@ -1,6 +1,8 @@
.histogrambox-container {
padding: 0vw;
position: absolute;
+ top: 0;
+ left:0;
text-align: center;
width: 100%;
height: 100%;
@@ -8,6 +10,7 @@
}
.histogrambox-xaxislabel {
position:absolute;
+ left:0;
width:100%;
text-align: center;
bottom:0;
@@ -19,11 +22,13 @@
position:absolute;
height:100%;
width: 25px;
+ left:0;
bottom:0;
background: lightgray;
}
.histogrambox-yaxislabel-text {
position:absolute;
+ left:0;
transform-origin: left;
transform: rotate(-90deg);
text-align: center;
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index c0f482e18..e8f8cce7c 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -8,304 +8,307 @@ import { CollectionView } from "../views/collections/CollectionView";
import { DocumentView } from "../views/nodes/DocumentView";
export function setupDrag(
- _reference: React.RefObject<HTMLDivElement>,
- docFunc: () => Document,
- removeFunc: (containingCollection: CollectionView) => void = () => {}
+ _reference: React.RefObject<HTMLDivElement>,
+ docFunc: () => Document,
+ removeFunc: (containingCollection: CollectionView) => void = () => { }
) {
- let onRowMove = action(
- (e: PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
+ let onRowMove = action(
+ (e: PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
- document.removeEventListener("pointermove", onRowMove);
- document.removeEventListener("pointerup", onRowUp);
- var dragData = new DragManager.DocumentDragData([docFunc()]);
- dragData.removeDocument = removeFunc;
- DragManager.StartDocumentDrag([_reference.current!], dragData);
- }
- );
- let onRowUp = action(
- (e: PointerEvent): void => {
- document.removeEventListener("pointermove", onRowMove);
- document.removeEventListener("pointerup", onRowUp);
- }
- );
- let onItemDown = (e: React.PointerEvent) => {
- // if (this.props.isSelected() || this.props.isTopMost) {
- if (e.button == 0) {
- e.stopPropagation();
- if (e.shiftKey) {
- CollectionDockingView.Instance.StartOtherDrag([docFunc()], e);
- } else {
- document.addEventListener("pointermove", onRowMove);
- document.addEventListener("pointerup", onRowUp);
- }
- }
- //}
- };
- return onItemDown;
+ document.removeEventListener("pointermove", onRowMove);
+ document.removeEventListener("pointerup", onRowUp);
+ var dragData = new DragManager.DocumentDragData([docFunc()]);
+ dragData.removeDocument = removeFunc;
+ DragManager.StartDocumentDrag([_reference.current!], dragData);
+ }
+ );
+ let onRowUp = action(
+ (e: PointerEvent): void => {
+ document.removeEventListener("pointermove", onRowMove);
+ document.removeEventListener("pointerup", onRowUp);
+ }
+ );
+ let onItemDown = (e: React.PointerEvent) => {
+ // if (this.props.isSelected() || this.props.isTopMost) {
+ if (e.button == 0) {
+ e.stopPropagation();
+ if (e.shiftKey) {
+ CollectionDockingView.Instance.StartOtherDrag([docFunc()], e);
+ } else {
+ document.addEventListener("pointermove", onRowMove);
+ document.addEventListener("pointerup", onRowUp);
+ }
+ }
+ //}
+ };
+ return onItemDown;
}
export namespace DragManager {
- export function Root() {
- const root = document.getElementById("root");
- if (!root) {
- throw new Error("No root element found");
+ export function Root() {
+ const root = document.getElementById("root");
+ if (!root) {
+ throw new Error("No root element found");
+ }
+ return root;
}
- return root;
- }
- let dragDiv: HTMLDivElement;
+ let dragDiv: HTMLDivElement;
- export enum DragButtons {
- Left = 1,
- Right = 2,
- Both = Left | Right
- }
+ export enum DragButtons {
+ Left = 1,
+ Right = 2,
+ Both = Left | Right
+ }
- interface DragOptions {
- handlers: DragHandlers;
+ interface DragOptions {
+ handlers: DragHandlers;
- hideSource: boolean | (() => boolean);
- }
+ hideSource: boolean | (() => boolean);
+ }
- export interface DragDropDisposer {
- (): void;
- }
+ export interface DragDropDisposer {
+ (): void;
+ }
- export class DragCompleteEvent {}
+ export class DragCompleteEvent { }
- export interface DragHandlers {
- dragComplete: (e: DragCompleteEvent) => void;
- }
+ export interface DragHandlers {
+ dragComplete: (e: DragCompleteEvent) => void;
+ }
- export interface DropOptions {
- handlers: DropHandlers;
- }
- export class DropEvent {
- constructor(
- readonly x: number,
- readonly y: number,
- readonly data: { [id: string]: any }
- ) {}
- }
+ export interface DropOptions {
+ handlers: DropHandlers;
+ }
+ export class DropEvent {
+ constructor(
+ readonly x: number,
+ readonly y: number,
+ readonly data: { [id: string]: any }
+ ) { }
+ }
- export interface DropHandlers {
- drop: (e: Event, de: DropEvent) => void;
- }
+ export interface DropHandlers {
+ drop: (e: Event, de: DropEvent) => void;
+ }
- export function MakeDropTarget(
- element: HTMLElement,
- options: DropOptions
- ): DragDropDisposer {
- if ("canDrop" in element.dataset) {
- throw new Error(
- "Element is already droppable, can't make it droppable again"
- );
+ export function MakeDropTarget(
+ element: HTMLElement,
+ options: DropOptions
+ ): DragDropDisposer {
+ if ("canDrop" in element.dataset) {
+ throw new Error(
+ "Element is already droppable, can't make it droppable again"
+ );
+ }
+ element.dataset["canDrop"] = "true";
+ const handler = (e: Event) => {
+ const ce = e as CustomEvent<DropEvent>;
+ options.handlers.drop(e, ce.detail);
+ };
+ element.addEventListener("dashOnDrop", handler);
+ return () => {
+ element.removeEventListener("dashOnDrop", handler);
+ delete element.dataset["canDrop"];
+ };
}
- element.dataset["canDrop"] = "true";
- const handler = (e: Event) => {
- const ce = e as CustomEvent<DropEvent>;
- options.handlers.drop(e, ce.detail);
- };
- element.addEventListener("dashOnDrop", handler);
- return () => {
- element.removeEventListener("dashOnDrop", handler);
- delete element.dataset["canDrop"];
- };
- }
- export class DocumentDragData {
- constructor(dragDoc: Document[]) {
- this.draggedDocuments = dragDoc;
- this.droppedDocuments = dragDoc;
+ export class DocumentDragData {
+ constructor(dragDoc: Document[]) {
+ this.draggedDocuments = dragDoc;
+ this.droppedDocuments = dragDoc;
+ }
+ draggedDocuments: Document[];
+ droppedDocuments: Document[];
+ xOffset?: number;
+ yOffset?: number;
+ aliasOnDrop?: boolean;
+ removeDocument?: (collectionDrop: CollectionView) => void;
+ [id: string]: any;
}
- draggedDocuments: Document[];
- droppedDocuments: Document[];
- xOffset?: number;
- yOffset?: number;
- aliasOnDrop?: boolean;
- removeDocument?: (collectionDrop: CollectionView) => void;
- [id: string]: any;
- }
- export function StartDocumentDrag(
- eles: HTMLElement[],
- dragData: DocumentDragData,
- options?: DragOptions
- ) {
- StartDrag(
- eles,
- dragData,
- options,
- (dropData: { [id: string]: any }) =>
- (dropData.droppedDocuments = dragData.aliasOnDrop
- ? dragData.draggedDocuments.map(d => d.CreateAlias())
- : dragData.draggedDocuments)
- );
- }
+ export function StartDocumentDrag(
+ eles: HTMLElement[],
+ dragData: DocumentDragData,
+ options?: DragOptions
+ ) {
+ StartDrag(
+ eles,
+ dragData,
+ options,
+ (dropData: { [id: string]: any }) =>
+ (dropData.droppedDocuments = dragData.aliasOnDrop
+ ? dragData.draggedDocuments.map(d => d.CreateAlias())
+ : dragData.draggedDocuments)
+ );
+ }
- export class LinkDragData {
- constructor(linkSourceDoc: DocumentView) {
- this.linkSourceDocumentView = linkSourceDoc;
+ export class LinkDragData {
+ constructor(linkSourceDoc: DocumentView) {
+ this.linkSourceDocumentView = linkSourceDoc;
+ }
+ droppedDocuments: Document[] = [];
+ linkSourceDocumentView: DocumentView;
+ [id: string]: any;
}
- linkSourceDocumentView: DocumentView;
- [id: string]: any;
- }
- export function StartLinkDrag(
- ele: HTMLElement,
- dragData: LinkDragData,
- options?: DragOptions
- ) {
- StartDrag([ele], dragData, options);
- }
- function StartDrag(
- eles: HTMLElement[],
- dragData: { [id: string]: any },
- options?: DragOptions,
- finishDrag?: (dropData: { [id: string]: any }) => void
- ) {
- if (!dragDiv) {
- dragDiv = document.createElement("div");
- dragDiv.className = "dragManager-dragDiv";
- DragManager.Root().appendChild(dragDiv);
+ export function StartLinkDrag(
+ ele: HTMLElement,
+ dragData: LinkDragData,
+ options?: DragOptions
+ ) {
+ StartDrag([ele], dragData, options);
}
+ function StartDrag(
+ eles: HTMLElement[],
+ dragData: { [id: string]: any },
+ options?: DragOptions,
+ finishDrag?: (dropData: { [id: string]: any }) => void
+ ) {
+ if (!dragDiv) {
+ dragDiv = document.createElement("div");
+ dragDiv.className = "dragManager-dragDiv";
+ DragManager.Root().appendChild(dragDiv);
+ }
- let scaleXs: number[] = [];
- let scaleYs: number[] = [];
- let xs: number[] = [];
- let ys: number[] = [];
+ let scaleXs: number[] = [];
+ let scaleYs: number[] = [];
+ let xs: number[] = [];
+ let ys: number[] = [];
- const docs: Document[] =
- dragData instanceof DocumentDragData ? dragData.draggedDocuments : [];
- let dragElements = eles.map(ele => {
- const w = ele.offsetWidth,
- h = ele.offsetHeight;
- const rect = ele.getBoundingClientRect();
- const scaleX = rect.width / w,
- scaleY = rect.height / h;
- let x = rect.left,
- y = rect.top;
- xs.push(x);
- ys.push(y);
- scaleXs.push(scaleX);
- scaleYs.push(scaleY);
- let dragElement = ele.cloneNode(true) as HTMLElement;
- dragElement.style.opacity = "0.7";
- dragElement.style.position = "absolute";
- dragElement.style.bottom = "";
- dragElement.style.left = "";
- dragElement.style.transformOrigin = "0 0";
- dragElement.style.zIndex = "1000";
- dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`;
- dragElement.style.width = `${rect.width / scaleX}px`;
- dragElement.style.height = `${rect.height / scaleY}px`;
+ const docs: Document[] =
+ dragData instanceof DocumentDragData ? dragData.draggedDocuments : [];
+ let dragElements = eles.map(ele => {
+ const w = ele.offsetWidth,
+ h = ele.offsetHeight;
+ const rect = ele.getBoundingClientRect();
+ const scaleX = rect.width / w,
+ scaleY = rect.height / h;
+ let x = rect.left,
+ y = rect.top;
+ xs.push(x);
+ ys.push(y);
+ scaleXs.push(scaleX);
+ scaleYs.push(scaleY);
+ let dragElement = ele.cloneNode(true) as HTMLElement;
+ dragElement.style.opacity = "0.7";
+ dragElement.style.position = "absolute";
+ dragElement.style.margin = "0";
+ dragElement.style.top = "0";
+ dragElement.style.bottom = "";
+ dragElement.style.left = "0";
+ dragElement.style.transformOrigin = "0 0";
+ dragElement.style.zIndex = "1000";
+ dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`;
+ dragElement.style.width = `${rect.width / scaleX}px`;
+ dragElement.style.height = `${rect.height / scaleY}px`;
- // bcz: PDFs don't show up if you clone them because they contain a canvas.
- // however, PDF's have a thumbnail field that contains an image of their canvas.
- // So we replace the pdf's canvas with the image thumbnail
- if (docs.length) {
- var pdfBox = dragElement.getElementsByClassName(
- "pdfBox-cont"
- )[0] as HTMLElement;
- let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField);
- if (pdfBox && pdfBox.childElementCount && thumbnail) {
- let img = new Image();
- img!.src = thumbnail.toString();
- img!.style.position = "absolute";
- img!.style.width = `${rect.width / scaleX}px`;
- img!.style.height = `${rect.height / scaleY}px`;
- pdfBox.replaceChild(img!, pdfBox.children[0]);
+ // bcz: PDFs don't show up if you clone them because they contain a canvas.
+ // however, PDF's have a thumbnail field that contains an image of their canvas.
+ // So we replace the pdf's canvas with the image thumbnail
+ if (docs.length) {
+ var pdfBox = dragElement.getElementsByClassName(
+ "pdfBox-cont"
+ )[0] as HTMLElement;
+ let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField);
+ if (pdfBox && pdfBox.childElementCount && thumbnail) {
+ let img = new Image();
+ img!.src = thumbnail.toString();
+ img!.style.position = "absolute";
+ img!.style.width = `${rect.width / scaleX}px`;
+ img!.style.height = `${rect.height / scaleY}px`;
+ pdfBox.replaceChild(img!, pdfBox.children[0]);
+ }
+ }
+
+ dragDiv.appendChild(dragElement);
+ return dragElement;
+ });
+
+ let hideSource = false;
+ if (options) {
+ if (typeof options.hideSource === "boolean") {
+ hideSource = options.hideSource;
+ } else {
+ hideSource = options.hideSource();
+ }
}
- }
+ eles.map(ele => (ele.hidden = hideSource));
- dragDiv.appendChild(dragElement);
- return dragElement;
- });
+ const moveHandler = (e: PointerEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ if (dragData instanceof DocumentDragData)
+ dragData.aliasOnDrop = e.ctrlKey || e.altKey;
+ if (e.shiftKey) {
+ abortDrag();
+ CollectionDockingView.Instance.StartOtherDrag(docs, {
+ pageX: e.pageX,
+ pageY: e.pageY,
+ preventDefault: () => { },
+ button: 0
+ });
+ }
+ dragElements.map(
+ (dragElement, i) =>
+ (dragElement.style.transform = `translate(${(xs[i] +=
+ e.movementX)}px, ${(ys[i] += e.movementY)}px) scale(${
+ scaleXs[i]
+ }, ${scaleYs[i]})`)
+ );
+ };
- let hideSource = false;
- if (options) {
- if (typeof options.hideSource === "boolean") {
- hideSource = options.hideSource;
- } else {
- hideSource = options.hideSource();
- }
+ const abortDrag = () => {
+ document.removeEventListener("pointermove", moveHandler, true);
+ document.removeEventListener("pointerup", upHandler);
+ dragElements.map(dragElement => dragDiv.removeChild(dragElement));
+ eles.map(ele => (ele.hidden = false));
+ };
+ const upHandler = (e: PointerEvent) => {
+ abortDrag();
+ FinishDrag(eles, e, dragData, options, finishDrag);
+ };
+ document.addEventListener("pointermove", moveHandler, true);
+ document.addEventListener("pointerup", upHandler);
}
- eles.map(ele => (ele.hidden = hideSource));
- const moveHandler = (e: PointerEvent) => {
- e.stopPropagation();
- e.preventDefault();
- if (dragData instanceof DocumentDragData)
- dragData.aliasOnDrop = e.ctrlKey || e.altKey;
- if (e.shiftKey) {
- abortDrag();
- CollectionDockingView.Instance.StartOtherDrag(docs, {
- pageX: e.pageX,
- pageY: e.pageY,
- preventDefault: () => {},
- button: 0
+ function FinishDrag(
+ dragEles: HTMLElement[],
+ e: PointerEvent,
+ dragData: { [index: string]: any },
+ options?: DragOptions,
+ finishDrag?: (dragData: { [index: string]: any }) => void
+ ) {
+ let removed = dragEles.map(dragEle => {
+ let parent = dragEle.parentElement;
+ if (parent) parent.removeChild(dragEle);
+ return [dragEle, parent];
});
- }
- dragElements.map(
- (dragElement, i) =>
- (dragElement.style.transform = `translate(${(xs[i] +=
- e.movementX)}px, ${(ys[i] += e.movementY)}px) scale(${
- scaleXs[i]
- }, ${scaleYs[i]})`)
- );
- };
-
- const abortDrag = () => {
- document.removeEventListener("pointermove", moveHandler, true);
- document.removeEventListener("pointerup", upHandler);
- dragElements.map(dragElement => dragDiv.removeChild(dragElement));
- eles.map(ele => (ele.hidden = false));
- };
- const upHandler = (e: PointerEvent) => {
- abortDrag();
- FinishDrag(eles, e, dragData, options, finishDrag);
- };
- document.addEventListener("pointermove", moveHandler, true);
- document.addEventListener("pointerup", upHandler);
- }
-
- function FinishDrag(
- dragEles: HTMLElement[],
- e: PointerEvent,
- dragData: { [index: string]: any },
- options?: DragOptions,
- finishDrag?: (dragData: { [index: string]: any }) => void
- ) {
- let removed = dragEles.map(dragEle => {
- let parent = dragEle.parentElement;
- if (parent) parent.removeChild(dragEle);
- return [dragEle, parent];
- });
- const target = document.elementFromPoint(e.x, e.y);
- removed.map(r => {
- let dragEle: HTMLElement = r[0]!;
- let parent: HTMLElement | null = r[1];
- if (parent) parent.appendChild(dragEle);
- });
- if (target) {
- if (finishDrag) finishDrag(dragData);
+ const target = document.elementFromPoint(e.x, e.y);
+ removed.map(r => {
+ let dragEle: HTMLElement = r[0]!;
+ let parent: HTMLElement | null = r[1];
+ if (parent) parent.appendChild(dragEle);
+ });
+ if (target) {
+ if (finishDrag) finishDrag(dragData);
- target.dispatchEvent(
- new CustomEvent<DropEvent>("dashOnDrop", {
- bubbles: true,
- detail: {
- x: e.x,
- y: e.y,
- data: dragData
- }
- })
- );
+ target.dispatchEvent(
+ new CustomEvent<DropEvent>("dashOnDrop", {
+ bubbles: true,
+ detail: {
+ x: e.x,
+ y: e.y,
+ data: dragData
+ }
+ })
+ );
- if (options) {
- options.handlers.dragComplete({});
- }
+ if (options) {
+ options.handlers.dragComplete({});
+ }
+ }
+ DocumentDecorations.Instance.Hidden = false;
}
- DocumentDecorations.Instance.Hidden = false;
- }
}
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 438659108..958c14491 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -3,48 +3,46 @@ import { DocumentView } from "../views/nodes/DocumentView";
import { Document } from "../../fields/Document";
export namespace SelectionManager {
- class Manager {
- @observable
- SelectedDocuments: Array<DocumentView> = [];
-
- @action
- SelectDoc(doc: DocumentView, ctrlPressed: boolean): void {
- // if doc is not in SelectedDocuments, add it
- if (!ctrlPressed) {
- manager.SelectedDocuments = [];
- }
-
- if (manager.SelectedDocuments.indexOf(doc) === -1) {
- manager.SelectedDocuments.push(doc);
- }
+ class Manager {
+ @observable
+ SelectedDocuments: Array<DocumentView> = [];
+
+ @action
+ SelectDoc(doc: DocumentView, ctrlPressed: boolean): void {
+ // if doc is not in SelectedDocuments, add it
+ if (!ctrlPressed) {
+ manager.SelectedDocuments = [];
+ }
+
+ if (manager.SelectedDocuments.indexOf(doc) === -1) {
+ manager.SelectedDocuments.push(doc);
+ }
+ }
}
- }
- const manager = new Manager();
+ const manager = new Manager();
- export function SelectDoc(doc: DocumentView, ctrlPressed: boolean): void {
- if (!doc.isMinimized()) {
- manager.SelectDoc(doc, ctrlPressed);
+ export function SelectDoc(doc: DocumentView, ctrlPressed: boolean): void {
+ manager.SelectDoc(doc, ctrlPressed);
}
- }
-
- export function IsSelected(doc: DocumentView): boolean {
- return manager.SelectedDocuments.indexOf(doc) !== -1;
- }
-
- export function DeselectAll(except?: Document): void {
- let found: DocumentView | undefined = undefined;
- if (except) {
- for (let i = 0; i < manager.SelectedDocuments.length; i++) {
- let view = manager.SelectedDocuments[i];
- if (view.props.Document == except) found = view;
- }
+
+ export function IsSelected(doc: DocumentView): boolean {
+ return manager.SelectedDocuments.indexOf(doc) !== -1;
+ }
+
+ export function DeselectAll(except?: Document): void {
+ let found: DocumentView | undefined = undefined;
+ if (except) {
+ for (let i = 0; i < manager.SelectedDocuments.length; i++) {
+ let view = manager.SelectedDocuments[i];
+ if (view.props.Document == except) found = view;
+ }
+ }
+ manager.SelectedDocuments.length = 0;
+ if (found) manager.SelectedDocuments.push(found);
}
- manager.SelectedDocuments.length = 0;
- if (found) manager.SelectedDocuments.push(found);
- }
- export function SelectedDocuments(): Array<DocumentView> {
- return manager.SelectedDocuments;
- }
+ export function SelectedDocuments(): Array<DocumentView> {
+ return manager.SelectedDocuments;
+ }
}
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index befe175b5..080c9fa1e 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -2,13 +2,16 @@
#documentDecorations-container {
position: absolute;
+ top: 0;
+ left:0;
display: grid;
z-index: 1000;
grid-template-rows: 20px 8px 1fr 8px;
- grid-template-columns: 8px 1fr 8px;
+ grid-template-columns: 8px 8px 1fr 8px;
pointer-events: none;
#documentDecorations-centerCont {
+ grid-column:3;
background: none;
}
@@ -19,6 +22,24 @@
}
#documentDecorations-topLeftResizer,
+ #documentDecorations-leftResizer,
+ #documentDecorations-bottomLeftResizer {
+ grid-column: 1
+ }
+
+ #documentDecorations-topResizer,
+ #documentDecorations-bottomResizer {
+ grid-column-start: 2;
+ grid-column-end: 4;
+ }
+
+ #documentDecorations-bottomRightResizer,
+ #documentDecorations-topRightResizer,
+ #documentDecorations-rightResizer {
+ grid-column:4
+ }
+
+ #documentDecorations-topLeftResizer,
#documentDecorations-bottomRightResizer {
cursor: nwse-resize;
}
@@ -39,15 +60,19 @@
}
.title{
background: lightblue;
- grid-column-start:2;
- grid-column-end: 4;
+ grid-column-start:3;
+ grid-column-end: 5;
pointer-events: auto;
}
}
.documentDecorations-minimizeButton {
- background: rgb(250, 57, 9);
+ background:$alt-accent;
+ opacity: 0.8;
+ grid-column-start: 1;
+ grid-column-end: 3;
pointer-events: all;
+ text-align: center;
}
.documentDecorations-background {
background: lightblue;
@@ -87,7 +112,8 @@
// }
// }
.linkFlyout {
- grid-column: 1/4
+ grid-column: 1/4;
+ margin-left: 25px;
}
.linkButton-empty:hover {
@@ -102,6 +128,31 @@
cursor: pointer;
}
+.linkButton-linker {
+ position:absolute;
+ bottom:0px;
+ left: 0px;
+ height: 20px;
+ width: 20px;
+ margin-top: 10px;
+ margin-right: 5px;
+ border-radius: 50%;
+ opacity: 0.9;
+ pointer-events: auto;
+ color: $dark-color;
+ border: $dark-color 1px solid;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ font-size: 75%;
+ transition: transform 0.2s;
+ text-align: center;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+.linkButton-tray {
+ grid-column: 1/4;
+}
.linkButton-empty {
height: 20px;
width: 20px;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index b74737ec9..a46087c9a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,10 +1,11 @@
-import { action, computed, observable } from "mobx";
+import { action, computed, observable, trace, runInAction } from "mobx";
import { observer } from "mobx-react";
import { Key } from "../../fields/Key";
//import ContentEditable from 'react-contenteditable'
import { KeyStore } from "../../fields/KeyStore";
import { ListField } from "../../fields/ListField";
import { NumberField } from "../../fields/NumberField";
+import { Document } from "../../fields/Document";
import { TextField } from "../../fields/TextField";
import { DragManager } from "../util/DragManager";
import { SelectionManager } from "../util/SelectionManager";
@@ -13,6 +14,7 @@ import './DocumentDecorations.scss';
import { DocumentView } from "./nodes/DocumentView";
import { LinkMenu } from "./nodes/LinkMenu";
import React = require("react");
+import { FieldWaiting } from "../../fields/Field";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -28,6 +30,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
private _linkBoxHeight = 30;
private _titleHeight = 20;
private _linkButton = React.createRef<HTMLDivElement>();
+ private _linkerButton = React.createRef<HTMLDivElement>();
//@observable private _title: string = this._documents[0].props.Document.Title;
@observable private _title: string = this._documents.length > 0 ? this._documents[0].props.Document.Title : "";
@observable private _fieldKey: Key = KeyStore.Title;
@@ -174,18 +177,40 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
}
- onLinkButtonDown = (e: React.PointerEvent): void => {
- // if ()
- // let linkMenu = new LinkMenu(SelectionManager.SelectedDocuments()[0]);
- // linkMenu.Hidden = false;
- console.log("down");
+ onLinkerButtonDown = (e: React.PointerEvent): void => {
+ e.stopPropagation();
+ document.removeEventListener("pointermove", this.onLinkerButtonMoved)
+ document.addEventListener("pointermove", this.onLinkerButtonMoved);
+ document.removeEventListener("pointerup", this.onLinkerButtonUp)
+ document.addEventListener("pointerup", this.onLinkerButtonUp);
+ }
+ onLinkerButtonUp = (e: PointerEvent): void => {
+ document.removeEventListener("pointermove", this.onLinkerButtonMoved)
+ document.removeEventListener("pointerup", this.onLinkerButtonUp)
+ e.stopPropagation();
+ }
+ onLinkerButtonMoved = (e: PointerEvent): void => {
+ if (this._linkerButton.current != null) {
+ document.removeEventListener("pointermove", this.onLinkerButtonMoved)
+ document.removeEventListener("pointerup", this.onLinkerButtonUp)
+ let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]);
+ DragManager.StartLinkDrag(this._linkerButton.current, dragData, {
+ handlers: {
+ dragComplete: action(() => { }),
+ },
+ hideSource: false
+ })
+ }
+ e.stopPropagation();
+ }
+
+ onLinkButtonDown = (e: React.PointerEvent): void => {
e.stopPropagation();
document.removeEventListener("pointermove", this.onLinkButtonMoved)
document.addEventListener("pointermove", this.onLinkButtonMoved);
document.removeEventListener("pointerup", this.onLinkButtonUp)
document.addEventListener("pointerup", this.onLinkButtonUp);
-
}
onLinkButtonUp = (e: PointerEvent): void => {
@@ -194,18 +219,32 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
e.stopPropagation();
}
-
onLinkButtonMoved = (e: PointerEvent): void => {
if (this._linkButton.current != null) {
document.removeEventListener("pointermove", this.onLinkButtonMoved)
- document.removeEventListener("pointerup", this.onLinkButtonUp)
- let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]);
- DragManager.StartLinkDrag(this._linkButton.current, dragData, {
- handlers: {
- dragComplete: action(() => { }),
- },
- hideSource: false
- })
+ document.removeEventListener("pointerup", this.onLinkButtonUp);
+
+ let sourceDoc = SelectionManager.SelectedDocuments()[0].props.Document;
+ let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document)
+ let draggedDocs = (srcTarg && srcTarg != FieldWaiting) ?
+ srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]).map(linkDoc =>
+ (linkDoc.GetT(KeyStore.LinkedToDocs, Document)) as Document) : [];
+ let draggedFromDocs = (srcTarg && srcTarg != FieldWaiting) ?
+ srcTarg.GetList(KeyStore.LinkedFromDocs, [] as Document[]).map(linkDoc =>
+ (linkDoc.GetT(KeyStore.LinkedFromDocs, Document)) as Document) : [];
+ draggedDocs.push(...draggedFromDocs);
+ if (draggedDocs.length) {
+ let dragData = new DragManager.DocumentDragData(draggedDocs.map(d => {
+ let annot = d.GetT(KeyStore.AnnotationOn, Document); // bcz: ... needs to change ... the annotationOn document may not have been retrieved yet...
+ return annot && annot != FieldWaiting ? annot : d;
+ }));
+ DragManager.StartDocumentDrag([this._linkButton.current], dragData, {
+ handlers: {
+ dragComplete: action(() => { }),
+ },
+ hideSource: false
+ })
+ }
}
e.stopPropagation();
}
@@ -298,7 +337,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
getValue = (): string => {
- console.log("value watched");
if (this._title === "changed" && this._documents.length > 0) {
let field = this._documents[0].props.Document.Get(this._fieldKey);
if (field instanceof TextField) {
@@ -338,8 +376,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
linkButton = (<Flyout
anchorPoint={anchorPoints.RIGHT_TOP}
content={
- <LinkMenu docView={selFirst} changeFlyout={this.changeFlyoutContent}>
- </LinkMenu>
+ <LinkMenu docView={selFirst} changeFlyout={this.changeFlyoutContent} />
}>
<div className={"linkButton-" + (selFirst.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []).length ? "nonempty" : "empty")} onPointerDown={this.onLinkButtonDown} >{linkCount}</div>
</Flyout>);
@@ -361,7 +398,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
opacity: this._opacity
}}>
- <div className="documentDecorations-minimizeButton" onPointerDown={this.onMinimizeDown}>v</div>
+ <div className="documentDecorations-minimizeButton" onPointerDown={this.onMinimizeDown}>...</div>
<input ref={this.keyinput} className="title" type="text" name="dynbox" value={this.getValue()} onChange={this.handleChange} onPointerDown={this.onPointerDown} onKeyPress={this.enterPressed} />
<div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
<div id="documentDecorations-topResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
@@ -373,8 +410,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
<div id="documentDecorations-bottomResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
<div id="documentDecorations-bottomRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div title="View Links" className="linkFlyout" ref={this._linkButton}>{linkButton}</div>
-
+ <div title="View Links" className="linkFlyout" ref={this._linkButton}> {linkButton} </div>
+ <div className="linkButton-linker" ref={this._linkerButton} onPointerDown={this.onLinkerButtonDown}>∞</div>
</div >
</div>
)
diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss
index 35c8ee942..c5a2a50cb 100644
--- a/src/client/views/InkingCanvas.scss
+++ b/src/client/views/InkingCanvas.scss
@@ -2,6 +2,8 @@
.inkingCanvas-paths-ink, .inkingCanvas-paths-markers, .inkingCanvas-noSelect, .inkingCanvas-canSelect {
position: absolute;
+ top: 0;
+ left:0;
width: 8192px;
height: 8192px;
cursor:"crosshair";
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index 698a9c617..594803aab 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -7,6 +7,9 @@ body {
overflow: hidden;
font-family: $sans-serif;
margin: 0;
+ position:absolute;
+ top: 0;
+ left:0;
}
#dash-title {
@@ -158,11 +161,15 @@ button:hover {
width:100%;
height:100%;
position:absolute;
+ top: 0;
+ left:0;
}
#mainContent-div {
width:100%;
height:100%;
position:absolute;
+ top: 0;
+ left:0;
}
#add-options-content {
display: table;
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 2706c3272..583d50c5b 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -3,7 +3,7 @@
}
.collectiondockingview-container {
- position: relative;
+ position: absolute;
top: 0;
left: 0;
overflow: hidden;
diff --git a/src/client/views/collections/CollectionPDFView.scss b/src/client/views/collections/CollectionPDFView.scss
index 0144625c1..0eca3f1cd 100644
--- a/src/client/views/collections/CollectionPDFView.scss
+++ b/src/client/views/collections/CollectionPDFView.scss
@@ -9,6 +9,8 @@
width: 100%;
height: 100%;
position: absolute;
+ top: 0;
+ left:0;
}
.collectionPdfView-backward {
diff --git a/src/client/views/collections/CollectionVideoView.scss b/src/client/views/collections/CollectionVideoView.scss
index cbb981b13..ed56ad268 100644
--- a/src/client/views/collections/CollectionVideoView.scss
+++ b/src/client/views/collections/CollectionVideoView.scss
@@ -3,6 +3,8 @@
width: 100%;
height: 100%;
position: absolute;
+ top: 0;
+ left:0;
}
.collectionVideoView-time{
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index 2b0689800..daeca69e2 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -17,6 +17,8 @@ import { NumberField } from "../../../fields/NumberField";
import request = require("request");
import { ServerUtils } from "../../../server/ServerUtil";
import { Server } from "../../Server";
+import { CollectionDockingView } from "./CollectionDockingView";
+import { runReactions } from "mobx/lib/internal";
export interface CollectionViewProps {
fieldKey: Key;
@@ -92,6 +94,24 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
e.stopPropagation();
return added;
}
+ if (de.data instanceof DragManager.LinkDragData) {
+ let sourceDoc: Document = de.data.linkSourceDocumentView.props.Document;
+ if (sourceDoc) runInAction(() => {
+ let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document)
+ if (srcTarg && srcTarg != FieldWaiting) {
+ let linkDocs = srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]);
+ linkDocs.map(linkDoc => {
+ let targDoc = linkDoc.GetT(KeyStore.LinkedToDocs, Document);
+ if (targDoc && targDoc != FieldWaiting) {
+ let dropdoc = targDoc.MakeDelegate();
+ de.data.droppedDocuments.push(dropdoc);
+ this.props.addDocument(dropdoc, false);
+ }
+ })
+ }
+ })
+ return true;
+ }
return false;
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index e84f0c5ad..3dfd74ec8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -23,10 +23,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
let l = this.props.LinkDocs;
let a = this.props.A;
let b = this.props.B;
- let x1 = a.GetNumber(KeyStore.X, 0) + a.GetNumber(KeyStore.Width, 0) / 2;
- let y1 = a.GetNumber(KeyStore.Y, 0) + a.GetNumber(KeyStore.Height, 0) / 2;
- let x2 = b.GetNumber(KeyStore.X, 0) + b.GetNumber(KeyStore.Width, 0) / 2;
- let y2 = b.GetNumber(KeyStore.Y, 0) + b.GetNumber(KeyStore.Height, 0) / 2;
+ let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Width, 0) / 2);
+ let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Height, 0) / 2);
+ let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Width, 0) / 2);
+ let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Height, 0) / 2);
return (
<line key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine" onPointerDown={this.onPointerDown}
style={{ strokeWidth: `${l.length * 5}` }}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
index 4341c82f7..30e158603 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.scss
@@ -1,6 +1,8 @@
.collectionfreeformlinksview-svgCanvas{
transform: translate(-10000px,-10000px);
position: absolute;
+ top: 0;
+ left: 0;
width: 20000px;
height: 20000px;
pointer-events: none;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 81d21d89a..79d520069 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -26,7 +26,7 @@
border: 0px solid $light-color-secondary;
border-radius: $border-radius;
box-sizing: border-box;
- position: relative;
+ position: absolute;
overflow: hidden;
top: 0;
left: 0;
@@ -41,12 +41,12 @@
.formattedTextBox-cont {
background: $light-color-secondary;
}
-
+
opacity: 0.99;
border: 0px solid transparent;
border-radius: $border-radius;
box-sizing: border-box;
- position:relative;
+ position:absolute;
overflow: hidden;
top: 0;
left: 0;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c5178f69d..3484e963e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -73,14 +73,17 @@ export class CollectionFreeFormView extends CollectionViewBase {
@action
drop = (e: Event, de: DragManager.DropEvent) => {
if (super.drop(e, de)) {
- if (de.data instanceof DragManager.DocumentDragData) {
- let screenX = de.x - (de.data.xOffset as number || 0);
- let screenY = de.y - (de.data.yOffset as number || 0);
+ let droppedDocs = de.data.droppedDocuments as Document[];
+ let xoff = de.data.xOffset as number || 0;
+ let yoff = de.data.yOffset as number || 0;
+ if (droppedDocs && droppedDocs.length) {
+ let screenX = de.x - xoff;
+ let screenY = de.y - yoff;
const [x, y] = this.getTransform().transformPoint(screenX, screenY);
- let dragDoc = de.data.draggedDocuments[0];
+ let dragDoc = de.data.droppedDocuments[0];
let dragX = dragDoc.GetNumber(KeyStore.X, 0);
let dragY = dragDoc.GetNumber(KeyStore.Y, 0);
- de.data.draggedDocuments.map(d => {
+ droppedDocs.map(d => {
let docX = d.GetNumber(KeyStore.X, 0);
let docY = d.GetNumber(KeyStore.Y, 0);
d.SetNumber(KeyStore.X, x + (docX - dragX));
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss
index 1ee3b244b..0b406e722 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss
@@ -1,6 +1,8 @@
.marqueeView {
position: absolute;
+ top:0;
+ left:0;
width:100%;
height:100%;
}
diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss b/src/client/views/collections/collectionFreeForm/PreviewCursor.scss
index 21210be2b..7a67c29bf 100644
--- a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss
+++ b/src/client/views/collections/collectionFreeForm/PreviewCursor.scss
@@ -3,9 +3,13 @@
color: black;
position: absolute;
transform-origin: left top;
+ top: 0;
+ left:0;
pointer-events: none;
}
.previewCursorView {
+ top: 0;
+ left:0;
position: absolute;
width:100%;
height:100%;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index d52b662bd..1a0f0cbbd 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -66,8 +66,12 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
return <DocumentView {...this.props}
ContentScaling={this.contentScaling}
ScreenToLocalTransform={this.getTransform}
+ PanelWidth={this.panelWidth}
+ PanelHeight={this.panelHeight}
/>
}
+ panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth();
+ panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight();
render() {
return (
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 127a6b535..5126e69f9 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -2,6 +2,8 @@
.documentView-node {
position: absolute;
+ top: 0;
+ left:0;
background: $light-color; //overflow: hidden;
&.minimized {
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index ad947afd5..830dfe6c6 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -1,12 +1,16 @@
.react-pdf__Page {
transform-origin: left top;
position: absolute;
+ top: 0;
+ left:0;
}
.react-pdf__Document {
position: absolute;
}
.pdfBox-buttonTray {
position:absolute;
+ top: 0;
+ left:0;
z-index: 25;
}
.pdfBox-contentContainer {
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index a535b2638..c73bc0c47 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -2,6 +2,8 @@
.webBox-cont {
padding: 0vw;
position: absolute;
+ top: 0;
+ left:0;
width: 100%;
height: 100%;
overflow: scroll;
diff --git a/src/fields/Document.ts b/src/fields/Document.ts
index 8e71019a4..92d03d765 100644
--- a/src/fields/Document.ts
+++ b/src/fields/Document.ts
@@ -9,415 +9,420 @@ import { Server } from "../client/Server";
import { Types } from "../server/Message";
import { UndoManager } from "../client/util/UndoManager";
import { HtmlField } from "./HtmlField";
+import { BooleanField } from "./BooleanField";
export class Document extends Field {
- //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field
- public fields: ObservableMap<
- string,
- { key: Key; field: Field }
- > = new ObservableMap();
- public _proxies: ObservableMap<string, FieldId> = new ObservableMap();
-
- constructor(id?: string, save: boolean = true) {
- super(id);
-
- if (save) {
- Server.UpdateField(this);
+ //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field
+ public fields: ObservableMap<
+ string,
+ { key: Key; field: Field }
+ > = new ObservableMap();
+ public _proxies: ObservableMap<string, FieldId> = new ObservableMap();
+
+ constructor(id?: string, save: boolean = true) {
+ super(id);
+
+ if (save) {
+ Server.UpdateField(this);
+ }
}
- }
- UpdateFromServer(data: [string, string][]) {
- for (const key in data) {
- const element = data[key];
- this._proxies.set(element[0], element[1]);
- }
- }
-
- public Width = () => {
- return this.GetNumber(KeyStore.Width, 0);
- };
- public Height = () => {
- return this.GetNumber(
- KeyStore.Height,
- this.GetNumber(KeyStore.NativeWidth, 0)
- ? (this.GetNumber(KeyStore.NativeHeight, 0) /
- this.GetNumber(KeyStore.NativeWidth, 0)) *
- this.GetNumber(KeyStore.Width, 0)
- : 0
- );
- };
- public Scale = () => {
- return this.GetNumber(KeyStore.Scale, 1);
- };
-
- @computed
- public get Title(): string {
- let title = this.Get(KeyStore.Title, true);
- if (title)
- if (title != FieldWaiting && title instanceof TextField)
- return title.Data;
- else return "-waiting-";
- let parTitle = this.GetT(KeyStore.Title, TextField);
- if (parTitle)
- if (parTitle != FieldWaiting) return parTitle.Data + ".alias";
- else return "-waiting-.alias";
- return "-untitled-";
- }
-
- @computed
- public get Fields() {
- return this.fields;
- }
-
- /**
- * Get the field in the document associated with the given key. If the
- * associated field has not yet been filled in from the server, a request
- * to the server will automatically be sent, the value will be filled in
- * when the request is completed, and {@link Field.ts#FieldWaiting} will be returned.
- * @param key - The key of the value to get
- * @param ignoreProto - If true, ignore any prototype this document
- * might have and only search for the value on this immediate document.
- * If false (default), search up the prototype chain, starting at this document,
- * for a document that has a field associated with the given key, and return the first
- * one found.
- *
- * @returns If the document does not have a field associated with the given key, returns `undefined`.
- * If the document does have an associated field, but the field has not been fetched from the server, returns {@link Field.ts#FieldWaiting}.
- * If the document does have an associated field, and the field has not been fetched from the server, returns the associated field.
- */
- Get(key: Key, ignoreProto: boolean = false): FieldValue<Field> {
- let field: FieldValue<Field>;
- if (ignoreProto) {
- if (this.fields.has(key.Id)) {
- field = this.fields.get(key.Id)!.field;
- } else if (this._proxies.has(key.Id)) {
- Server.GetDocumentField(this, key);
- /*
- The field might have been instantly filled from the cache
- Maybe we want to just switch back to returning the value
- from Server.GetDocumentField if it's in the cache
- */
- if (this.fields.has(key.Id)) {
- field = this.fields.get(key.Id)!.field;
- } else {
- field = FieldWaiting;
+ UpdateFromServer(data: [string, string][]) {
+ for (const key in data) {
+ const element = data[key];
+ this._proxies.set(element[0], element[1]);
}
- }
- } else {
- let doc: FieldValue<Document> = this;
- while (doc && doc != FieldWaiting && field != FieldWaiting) {
- let curField = doc.fields.get(key.Id);
- let curProxy = doc._proxies.get(key.Id);
- if (!curField || (curProxy && curField.field.Id !== curProxy)) {
- if (curProxy) {
- Server.GetDocumentField(doc, key);
- /*
+ }
+
+ public Width = () => {
+ return this.GetNumber(KeyStore.Width, 0);
+ };
+ public Height = () => {
+ return this.GetNumber(
+ KeyStore.Height,
+ this.GetNumber(KeyStore.NativeWidth, 0)
+ ? (this.GetNumber(KeyStore.NativeHeight, 0) /
+ this.GetNumber(KeyStore.NativeWidth, 0)) *
+ this.GetNumber(KeyStore.Width, 0)
+ : 0
+ );
+ };
+ public Scale = () => {
+ return this.GetNumber(KeyStore.Scale, 1);
+ };
+
+ @computed
+ public get Title(): string {
+ let title = this.Get(KeyStore.Title, true);
+ if (title)
+ if (title != FieldWaiting && title instanceof TextField)
+ return title.Data;
+ else return "-waiting-";
+ let parTitle = this.GetT(KeyStore.Title, TextField);
+ if (parTitle)
+ if (parTitle != FieldWaiting) return parTitle.Data + ".alias";
+ else return "-waiting-.alias";
+ return "-untitled-";
+ }
+
+ @computed
+ public get Fields() {
+ return this.fields;
+ }
+
+ /**
+ * Get the field in the document associated with the given key. If the
+ * associated field has not yet been filled in from the server, a request
+ * to the server will automatically be sent, the value will be filled in
+ * when the request is completed, and {@link Field.ts#FieldWaiting} will be returned.
+ * @param key - The key of the value to get
+ * @param ignoreProto - If true, ignore any prototype this document
+ * might have and only search for the value on this immediate document.
+ * If false (default), search up the prototype chain, starting at this document,
+ * for a document that has a field associated with the given key, and return the first
+ * one found.
+ *
+ * @returns If the document does not have a field associated with the given key, returns `undefined`.
+ * If the document does have an associated field, but the field has not been fetched from the server, returns {@link Field.ts#FieldWaiting}.
+ * If the document does have an associated field, and the field has not been fetched from the server, returns the associated field.
+ */
+ Get(key: Key, ignoreProto: boolean = false): FieldValue<Field> {
+ let field: FieldValue<Field>;
+ if (ignoreProto) {
+ if (this.fields.has(key.Id)) {
+ field = this.fields.get(key.Id)!.field;
+ } else if (this._proxies.has(key.Id)) {
+ Server.GetDocumentField(this, key);
+ /*
The field might have been instantly filled from the cache
Maybe we want to just switch back to returning the value
from Server.GetDocumentField if it's in the cache
*/
- if (this.fields.has(key.Id)) {
- field = this.fields.get(key.Id)!.field;
- } else {
- field = FieldWaiting;
+ if (this.fields.has(key.Id)) {
+ field = this.fields.get(key.Id)!.field;
+ } else {
+ field = FieldWaiting;
+ }
}
- break;
- }
- if (
- doc.fields.has(KeyStore.Prototype.Id) ||
- doc._proxies.has(KeyStore.Prototype.Id)
- ) {
- doc = doc.GetPrototype();
- } else {
- break;
- }
} else {
- field = curField.field;
- break;
+ let doc: FieldValue<Document> = this;
+ while (doc && doc != FieldWaiting && field != FieldWaiting) {
+ let curField = doc.fields.get(key.Id);
+ let curProxy = doc._proxies.get(key.Id);
+ if (!curField || (curProxy && curField.field.Id !== curProxy)) {
+ if (curProxy) {
+ Server.GetDocumentField(doc, key);
+ /*
+ The field might have been instantly filled from the cache
+ Maybe we want to just switch back to returning the value
+ from Server.GetDocumentField if it's in the cache
+ */
+ if (this.fields.has(key.Id)) {
+ field = this.fields.get(key.Id)!.field;
+ } else {
+ field = FieldWaiting;
+ }
+ break;
+ }
+ if (
+ doc.fields.has(KeyStore.Prototype.Id) ||
+ doc._proxies.has(KeyStore.Prototype.Id)
+ ) {
+ doc = doc.GetPrototype();
+ } else {
+ break;
+ }
+ } else {
+ field = curField.field;
+ break;
+ }
+ }
+ if (doc == FieldWaiting) field = FieldWaiting;
}
- }
- if (doc == FieldWaiting) field = FieldWaiting;
+
+ return field;
}
- return field;
- }
-
- /**
- * Tries to get the field associated with the given key, and if there is an
- * associated field, calls the given callback with that field.
- * @param key - The key of the value to get
- * @param callback - A function that will be called with the associated field, if it exists,
- * once it is fetched from the server (this may be immediately if the field has already been fetched).
- * Note: The callback will not be called if there is no associated field.
- * @returns `true` if the field exists on the document and `callback` will be called, and `false` otherwise
- */
- GetAsync(key: Key, callback: (field: Opt<Field>) => void): void {
- //TODO: This currently doesn't deal with prototypes
- let field = this.fields.get(key.Id);
- if (field && field.field) {
- callback(field.field);
- } else if (this._proxies.has(key.Id)) {
- Server.GetDocumentField(this, key, callback);
- } else if (this._proxies.has(KeyStore.Prototype.Id)) {
- this.GetTAsync(KeyStore.Prototype, Document, proto => {
- if (proto) {
- proto.GetAsync(key, callback);
+ /**
+ * Tries to get the field associated with the given key, and if there is an
+ * associated field, calls the given callback with that field.
+ * @param key - The key of the value to get
+ * @param callback - A function that will be called with the associated field, if it exists,
+ * once it is fetched from the server (this may be immediately if the field has already been fetched).
+ * Note: The callback will not be called if there is no associated field.
+ * @returns `true` if the field exists on the document and `callback` will be called, and `false` otherwise
+ */
+ GetAsync(key: Key, callback: (field: Opt<Field>) => void): void {
+ //TODO: This currently doesn't deal with prototypes
+ let field = this.fields.get(key.Id);
+ if (field && field.field) {
+ callback(field.field);
+ } else if (this._proxies.has(key.Id)) {
+ Server.GetDocumentField(this, key, callback);
+ } else if (this._proxies.has(KeyStore.Prototype.Id)) {
+ this.GetTAsync(KeyStore.Prototype, Document, proto => {
+ if (proto) {
+ proto.GetAsync(key, callback);
+ } else {
+ callback(undefined);
+ }
+ });
} else {
- callback(undefined);
+ callback(undefined);
}
- });
- } else {
- callback(undefined);
}
- }
-
- GetTAsync<T extends Field>(key: Key, ctor: { new (): T }): Promise<Opt<T>>;
- GetTAsync<T extends Field>(
- key: Key,
- ctor: { new (): T },
- callback: (field: Opt<T>) => void
- ): void;
- GetTAsync<T extends Field>(
- key: Key,
- ctor: { new (): T },
- callback?: (field: Opt<T>) => void
- ): Promise<Opt<T>> | void {
- let fn = (cb: (field: Opt<T>) => void) => {
- return this.GetAsync(key, field => {
- cb(Cast(field, ctor));
- });
- };
- if (callback) {
- fn(callback);
- } else {
- return new Promise(res => fn(res));
+
+ GetTAsync<T extends Field>(key: Key, ctor: { new(): T }): Promise<Opt<T>>;
+ GetTAsync<T extends Field>(
+ key: Key,
+ ctor: { new(): T },
+ callback: (field: Opt<T>) => void
+ ): void;
+ GetTAsync<T extends Field>(
+ key: Key,
+ ctor: { new(): T },
+ callback?: (field: Opt<T>) => void
+ ): Promise<Opt<T>> | void {
+ let fn = (cb: (field: Opt<T>) => void) => {
+ return this.GetAsync(key, field => {
+ cb(Cast(field, ctor));
+ });
+ };
+ if (callback) {
+ fn(callback);
+ } else {
+ return new Promise(res => fn(res));
+ }
}
- }
-
- /**
- * Same as {@link Document#GetAsync}, except a field of the given type
- * will be created if there is no field associated with the given key,
- * or the field associated with the given key is not of the given type.
- * @param ctor - Constructor of the field type to get. E.g., TextField, ImageField, etc.
- */
- GetOrCreateAsync<T extends Field>(
- key: Key,
- ctor: { new (): T },
- callback: (field: T) => void
- ): void {
- //This currently doesn't deal with prototypes
- if (this._proxies.has(key.Id)) {
- Server.GetDocumentField(this, key, field => {
- if (field && field instanceof ctor) {
- callback(field);
+
+ /**
+ * Same as {@link Document#GetAsync}, except a field of the given type
+ * will be created if there is no field associated with the given key,
+ * or the field associated with the given key is not of the given type.
+ * @param ctor - Constructor of the field type to get. E.g., TextField, ImageField, etc.
+ */
+ GetOrCreateAsync<T extends Field>(
+ key: Key,
+ ctor: { new(): T },
+ callback: (field: T) => void
+ ): void {
+ //This currently doesn't deal with prototypes
+ if (this._proxies.has(key.Id)) {
+ Server.GetDocumentField(this, key, field => {
+ if (field && field instanceof ctor) {
+ callback(field);
+ } else {
+ let newField = new ctor();
+ this.Set(key, newField);
+ callback(newField);
+ }
+ });
} else {
- let newField = new ctor();
- this.Set(key, newField);
- callback(newField);
+ let newField = new ctor();
+ this.Set(key, newField);
+ callback(newField);
}
- });
- } else {
- let newField = new ctor();
- this.Set(key, newField);
- callback(newField);
}
- }
-
- /**
- * Same as {@link Document#Get}, except that it will additionally
- * check if the field is of the given type.
- * @param ctor - Constructor of the field type to get. E.g., `TextField`, `ImageField`, etc.
- * @returns Same as {@link Document#Get}, except will return `undefined`
- * if there is an associated field but it is of the wrong type.
- */
- GetT<T extends Field = Field>(
- key: Key,
- ctor: { new (...args: any[]): T },
- ignoreProto: boolean = false
- ): FieldValue<T> {
- var getfield = this.Get(key, ignoreProto);
- if (getfield != FieldWaiting) {
- return Cast(getfield, ctor);
+
+ /**
+ * Same as {@link Document#Get}, except that it will additionally
+ * check if the field is of the given type.
+ * @param ctor - Constructor of the field type to get. E.g., `TextField`, `ImageField`, etc.
+ * @returns Same as {@link Document#Get}, except will return `undefined`
+ * if there is an associated field but it is of the wrong type.
+ */
+ GetT<T extends Field = Field>(
+ key: Key,
+ ctor: { new(...args: any[]): T },
+ ignoreProto: boolean = false
+ ): FieldValue<T> {
+ var getfield = this.Get(key, ignoreProto);
+ if (getfield != FieldWaiting) {
+ return Cast(getfield, ctor);
+ }
+ return FieldWaiting;
}
- return FieldWaiting;
- }
-
- GetOrCreate<T extends Field>(
- key: Key,
- ctor: { new (): T },
- ignoreProto: boolean = false
- ): T {
- const field = this.GetT(key, ctor, ignoreProto);
- if (field && field != FieldWaiting) {
- return field;
+
+ GetOrCreate<T extends Field>(
+ key: Key,
+ ctor: { new(): T },
+ ignoreProto: boolean = false
+ ): T {
+ const field = this.GetT(key, ctor, ignoreProto);
+ if (field && field != FieldWaiting) {
+ return field;
+ }
+ const newField = new ctor();
+ this.Set(key, newField);
+ return newField;
}
- const newField = new ctor();
- this.Set(key, newField);
- return newField;
- }
-
- GetData<T, U extends Field & { Data: T }>(
- key: Key,
- ctor: { new (): U },
- defaultVal: T
- ): T {
- let val = this.Get(key);
- let vval = val && val instanceof ctor ? val.Data : defaultVal;
- return vval;
- }
-
- GetHtml(key: Key, defaultVal: string): string {
- return this.GetData(key, HtmlField, defaultVal);
- }
-
- GetNumber(key: Key, defaultVal: number): number {
- return this.GetData(key, NumberField, defaultVal);
- }
-
- GetText(key: Key, defaultVal: string): string {
- return this.GetData(key, TextField, defaultVal);
- }
-
- GetList<T extends Field>(key: Key, defaultVal: T[]): T[] {
- return this.GetData<T[], ListField<T>>(key, ListField, defaultVal);
- }
-
- @action
- Set(key: Key, field: Field | undefined, setOnPrototype = false): void {
- let old = this.fields.get(key.Id);
- let oldField = old ? old.field : undefined;
- if (setOnPrototype) {
- this.SetOnPrototype(key, field);
- } else {
- if (field) {
- this.fields.set(key.Id, { key, field });
- this._proxies.set(key.Id, field.Id);
- // Server.AddDocumentField(this, key, field);
- } else {
- this.fields.delete(key.Id);
- this._proxies.delete(key.Id);
- // Server.DeleteDocumentField(this, key);
- }
- Server.UpdateField(this);
+
+ GetData<T, U extends Field & { Data: T }>(
+ key: Key,
+ ctor: { new(): U },
+ defaultVal: T
+ ): T {
+ let val = this.Get(key);
+ let vval = val && val instanceof ctor ? val.Data : defaultVal;
+ return vval;
}
- if (oldField || field) {
- UndoManager.AddEvent({
- undo: () => this.Set(key, oldField, setOnPrototype),
- redo: () => this.Set(key, field, setOnPrototype)
- });
+
+ GetHtml(key: Key, defaultVal: string): string {
+ return this.GetData(key, HtmlField, defaultVal);
}
- }
-
- @action
- SetOnPrototype(key: Key, field: Field | undefined): void {
- this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => {
- f && f.Set(key, field);
- });
- }
-
- @action
- SetDataOnPrototype<T, U extends Field & { Data: T }>(
- key: Key,
- value: T,
- ctor: { new (): U },
- replaceWrongType = true
- ) {
- this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => {
- f && f.SetData(key, value, ctor);
- });
- }
-
- @action
- SetData<T, U extends Field & { Data: T }>(
- key: Key,
- value: T,
- ctor: { new (data: T): U },
- replaceWrongType = true
- ) {
- let field = this.Get(key, true);
- if (field instanceof ctor) {
- field.Data = value;
- } else if (!field || replaceWrongType) {
- let newField = new ctor(value);
- // newField.Data = value;
- this.Set(key, newField);
+
+ GetBoolean(key: Key, defaultVal: boolean): boolean {
+ return this.GetData(key, BooleanField, defaultVal);
}
- }
-
- @action
- SetText(key: Key, value: string, replaceWrongType = true) {
- this.SetData(key, value, TextField, replaceWrongType);
- }
-
- @action
- SetNumber(key: Key, value: number, replaceWrongType = true) {
- this.SetData(key, value, NumberField, replaceWrongType);
- }
-
- GetPrototype(): FieldValue<Document> {
- return this.GetT(KeyStore.Prototype, Document, true);
- }
-
- GetAllPrototypes(): Document[] {
- let protos: Document[] = [];
- let doc: FieldValue<Document> = this;
- while (doc && doc != FieldWaiting) {
- protos.push(doc);
- doc = doc.GetPrototype();
+
+ GetNumber(key: Key, defaultVal: number): number {
+ return this.GetData(key, NumberField, defaultVal);
+ }
+
+ GetText(key: Key, defaultVal: string): string {
+ return this.GetData(key, TextField, defaultVal);
+ }
+
+ GetList<T extends Field>(key: Key, defaultVal: T[]): T[] {
+ return this.GetData<T[], ListField<T>>(key, ListField, defaultVal);
+ }
+
+ @action
+ Set(key: Key, field: Field | undefined, setOnPrototype = false): void {
+ let old = this.fields.get(key.Id);
+ let oldField = old ? old.field : undefined;
+ if (setOnPrototype) {
+ this.SetOnPrototype(key, field);
+ } else {
+ if (field) {
+ this.fields.set(key.Id, { key, field });
+ this._proxies.set(key.Id, field.Id);
+ // Server.AddDocumentField(this, key, field);
+ } else {
+ this.fields.delete(key.Id);
+ this._proxies.delete(key.Id);
+ // Server.DeleteDocumentField(this, key);
+ }
+ Server.UpdateField(this);
+ }
+ if (oldField || field) {
+ UndoManager.AddEvent({
+ undo: () => this.Set(key, oldField, setOnPrototype),
+ redo: () => this.Set(key, field, setOnPrototype)
+ });
+ }
+ }
+
+ @action
+ SetOnPrototype(key: Key, field: Field | undefined): void {
+ this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => {
+ f && f.Set(key, field);
+ });
+ }
+
+ @action
+ SetDataOnPrototype<T, U extends Field & { Data: T }>(
+ key: Key,
+ value: T,
+ ctor: { new(): U },
+ replaceWrongType = true
+ ) {
+ this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => {
+ f && f.SetData(key, value, ctor);
+ });
+ }
+
+ @action
+ SetData<T, U extends Field & { Data: T }>(
+ key: Key,
+ value: T,
+ ctor: { new(data: T): U },
+ replaceWrongType = true
+ ) {
+ let field = this.Get(key, true);
+ if (field instanceof ctor) {
+ field.Data = value;
+ } else if (!field || replaceWrongType) {
+ let newField = new ctor(value);
+ // newField.Data = value;
+ this.Set(key, newField);
+ }
+ }
+
+ @action
+ SetText(key: Key, value: string, replaceWrongType = true) {
+ this.SetData(key, value, TextField, replaceWrongType);
+ }
+
+ @action
+ SetNumber(key: Key, value: number, replaceWrongType = true) {
+ this.SetData(key, value, NumberField, replaceWrongType);
+ }
+
+ GetPrototype(): FieldValue<Document> {
+ return this.GetT(KeyStore.Prototype, Document, true);
+ }
+
+ GetAllPrototypes(): Document[] {
+ let protos: Document[] = [];
+ let doc: FieldValue<Document> = this;
+ while (doc && doc != FieldWaiting) {
+ protos.push(doc);
+ doc = doc.GetPrototype();
+ }
+ return protos;
+ }
+
+ CreateAlias(id?: string): Document {
+ let alias = new Document(id);
+ this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => {
+ f && alias.Set(KeyStore.Prototype, f);
+ });
+
+ return alias;
+ }
+
+ MakeDelegate(id?: string): Document {
+ let delegate = new Document(id);
+
+ delegate.Set(KeyStore.Prototype, this);
+
+ return delegate;
+ }
+
+ ToScriptString(): string {
+ return "";
+ }
+
+ TrySetValue(value: any): boolean {
+ throw new Error("Method not implemented.");
+ }
+ GetValue() {
+ return this.Title;
+ var title =
+ (this._proxies.has(KeyStore.Title.Id) ? "???" : this.Title) +
+ "(" +
+ this.Id +
+ ")";
+ return title;
+ //throw new Error("Method not implemented.");
+ }
+ Copy(): Field {
+ throw new Error("Method not implemented.");
+ }
+
+ ToJson(): { type: Types; data: [string, string][]; _id: string } {
+ let fields: [string, string][] = [];
+ this._proxies.forEach((field, key) => {
+ if (field) {
+ fields.push([key, field as string]);
+ }
+ });
+
+ return {
+ type: Types.Document,
+ data: fields,
+ _id: this.Id
+ };
}
- return protos;
- }
-
- CreateAlias(id?: string): Document {
- let alias = new Document(id);
- this.GetTAsync(KeyStore.Prototype, Document, (f: Opt<Document>) => {
- f && alias.Set(KeyStore.Prototype, f);
- });
-
- return alias;
- }
-
- MakeDelegate(id?: string): Document {
- let delegate = new Document(id);
-
- delegate.Set(KeyStore.Prototype, this);
-
- return delegate;
- }
-
- ToScriptString(): string {
- return "";
- }
-
- TrySetValue(value: any): boolean {
- throw new Error("Method not implemented.");
- }
- GetValue() {
- return this.Title;
- var title =
- (this._proxies.has(KeyStore.Title.Id) ? "???" : this.Title) +
- "(" +
- this.Id +
- ")";
- return title;
- //throw new Error("Method not implemented.");
- }
- Copy(): Field {
- throw new Error("Method not implemented.");
- }
-
- ToJson(): { type: Types; data: [string, string][]; _id: string } {
- let fields: [string, string][] = [];
- this._proxies.forEach((field, key) => {
- if (field) {
- fields.push([key, field as string]);
- }
- });
-
- return {
- type: Types.Document,
- data: fields,
- _id: this.Id
- };
- }
}