aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json4
-rw-r--r--src/Utils.ts57
-rw-r--r--src/client/views/DocumentDecorations.tsx4
-rw-r--r--src/client/views/InkingStroke.tsx18
-rw-r--r--src/client/views/PreviewCursor.scss1
-rw-r--r--src/client/views/PreviewCursor.tsx30
-rw-r--r--src/client/views/Touchable.tsx2
-rw-r--r--src/client/views/collections/ParentDocumentSelector.tsx1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx34
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx55
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss11
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx47
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx13
-rw-r--r--src/client/views/nodes/DocumentView.tsx26
-rw-r--r--src/client/views/nodes/FontIconBox.tsx2
-rw-r--r--src/client/views/nodes/FormattedTextBox.scss24
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx66
-rw-r--r--src/client/views/nodes/ImageBox.scss1
-rw-r--r--src/client/views/nodes/ImageBox.tsx7
-rw-r--r--src/client/views/nodes/PDFBox.scss49
-rw-r--r--src/client/views/nodes/PDFBox.tsx11
-rw-r--r--src/client/views/nodes/VideoBox.scss1
-rw-r--r--src/client/views/nodes/VideoBox.tsx2
-rw-r--r--src/client/views/pdf/PDFViewer.tsx12
-rw-r--r--src/new_fields/documentSchemas.ts2
-rw-r--r--src/new_fields/util.ts6
26 files changed, 311 insertions, 175 deletions
diff --git a/package.json b/package.json
index 591c8cff3..393df8574 100644
--- a/package.json
+++ b/package.json
@@ -159,10 +159,10 @@
"jsx-to-string": "^1.4.0",
"lodash": "^4.17.15",
"mobile-detect": "^1.4.3",
- "mobx": "^5.9.0",
+ "mobx": "^5.15.0",
"mobx-react": "^5.3.5",
"mobx-react-devtools": "^6.1.1",
- "mobx-utils": "^5.4.0",
+ "mobx-utils": "^5.5.2",
"mongodb": "^3.1.13",
"mongoose": "^5.6.4",
"node-sass": "^4.12.0",
diff --git a/src/Utils.ts b/src/Utils.ts
index fc12c1e14..b60e9e023 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -159,6 +159,63 @@ export namespace Utils {
return Math.max(lower, Math.min(upper, n));
}
+ export function distanceBetweenHorizontalLines(xs: number, xe: number, y: number, xs2: number, xe2: number, y2: number): [number, number[]] {
+ if ((xs2 < xs && xe2 > xs) || (xs2 < xe && xe2 > xe) || (xs2 > xs && xe2 < xe)) return [Math.abs(y - y2), [Math.max(xs, xs2), y, Math.min(xe, xe2), y]];
+ if (xe2 < xs) return [Math.sqrt((xe2 - xs) * (xe2 - xs) + (y2 - y) * (y2 - y)), [xs, y, xs, y]];
+ //if (xs2 > xe)
+ return [Math.sqrt((xs2 - xe) * (xs2 - xe) + (y2 - y) * (y2 - y)), [xe, y, xe, y]];
+ }
+ export function distanceBetweenVerticalLines(x: number, ys: number, ye: number, x2: number, ys2: number, ye2: number): [number, number[]] {
+ if ((ys2 < ys && ye2 > ys) || (ys2 < ye && ye2 > ye) || (ys2 > ys && ye2 < ye)) return [Math.abs(x - x2), [x, Math.max(ys, ys2), x, Math.min(ye, ye2)]];
+ if (ye2 < ys) return [Math.sqrt((ye2 - ys) * (ye2 - ys) + (x2 - x) * (x2 - x)), [x, ys, x, ys]];
+ //if (ys2 > ye)
+ return [Math.sqrt((ys2 - ye) * (ys2 - ye) + (x2 - x) * (x2 - x)), [x, ye, x, ye]];
+ }
+
+ function project(px: number, py: number, ax: number, ay: number, bx: number, by: number) {
+
+ if (ax === bx && ay === by) return { point: { x: ax, y: ay }, left: false, dot: 0, t: 0 };
+ var atob = { x: bx - ax, y: by - ay };
+ var atop = { x: px - ax, y: py - ay };
+ var len = atob.x * atob.x + atob.y * atob.y;
+ var dot = atop.x * atob.x + atop.y * atob.y;
+ var t = Math.min(1, Math.max(0, dot / len));
+
+ dot = (bx - ax) * (py - ay) - (by - ay) * (px - ax);
+
+ return {
+ point: {
+ x: ax + atob.x * t,
+ y: ay + atob.y * t
+ },
+ left: dot < 1,
+ dot: dot,
+ t: t
+ };
+ }
+
+ export function closestPtBetweenRectangles(l: number, t: number, w: number, h: number,
+ l1: number, t1: number, w1: number, h1: number,
+ x: number, y: number) {
+ var r = l + w,
+ b = t + h;
+ var r1 = l1 + w1,
+ b1 = t1 + h1;
+ let hsegs = [[l, r, t, l1, r1, t1], [l, r, b, l1, r1, t1], [l, r, t, l1, r1, b1], [l, r, b, l1, r1, b1]];
+ let vsegs = [[l, t, b, l1, t1, b1], [r, t, b, l1, t1, b1], [l, t, b, r1, t1, b1], [r, t, b, r1, t1, b1]];
+ let res = hsegs.reduce((closest, seg) => {
+ let res = distanceBetweenHorizontalLines(seg[0], seg[1], seg[2], seg[3], seg[4], seg[5]);
+ return (res[0] < closest[0]) ? res : closest;
+ }, [Number.MAX_VALUE, []] as [number, number[]]);
+ let fres = vsegs.reduce((closest, seg) => {
+ let res = distanceBetweenVerticalLines(seg[0], seg[1], seg[2], seg[3], seg[4], seg[5]);
+ return (res[0] < closest[0]) ? res : closest;
+ }, res);
+
+ let near = project(x, y, fres[1][0], fres[1][1], fres[1][2], fres[1][3]);
+ return project(near.point.x, near.point.y, fres[1][0], fres[1][1], fres[1][2], fres[1][3]);
+ }
+
export function getNearestPointInPerimeter(l: number, t: number, w: number, h: number, x: number, y: number) {
var r = l + w,
b = t + h;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 210fa40dc..66f47147f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -463,7 +463,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
break;
}
- SelectionManager.SelectedDocuments().forEach(element => {
+ SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => {
if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) {
let doc = PositionDocument(element.props.Document);
let layoutDoc = PositionDocument(Doc.Layout(element.props.Document));
@@ -509,7 +509,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
dH && layoutDoc.autoHeight && (layoutDoc.autoHeight = false);
}
}
- });
+ }));
}
@action
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 74211cc90..723b8cac4 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -35,7 +35,6 @@ export class InkingStroke extends DocExtendableComponent<FieldViewProps, InkDocu
@computed get PanelHeight() { return this.props.PanelHeight(); }
render() {
- // let pathData = this.parseData(this.props.line);
let data: InkData = Cast(this.Document.data, InkField)?.inkData ?? [];
let xs = data.map(p => p.x);
let ys = data.map(p => p.y);
@@ -48,15 +47,12 @@ export class InkingStroke extends DocExtendableComponent<FieldViewProps, InkDocu
let height = bottom - top;
let scaleX = this.PanelWidth / width;
let scaleY = this.PanelHeight / height;
- // let pathlength = this.props.count; // bcz: this is needed to force reactions to the line's data changes
- return (
- <svg width={width} height={height} style={{
- transformOrigin: "top left",
- transform: `translate(${left}px, ${top}px) scale(${scaleX}, ${scaleY})`,
- mixBlendMode: this.Document.tool === InkTool.Highlighter ? "multiply" : "unset"
- }}>
- {points}
- </svg>
- );
+ return <svg width={width} height={height} style={{
+ transformOrigin: "top left",
+ transform: `translate(${left}px, ${top}px) scale(${scaleX}, ${scaleY})`,
+ mixBlendMode: this.Document.tool === InkTool.Highlighter ? "multiply" : "unset"
+ }}>
+ {points}
+ </svg>;
}
} \ No newline at end of file
diff --git a/src/client/views/PreviewCursor.scss b/src/client/views/PreviewCursor.scss
index 20f9b9a49..d384fd284 100644
--- a/src/client/views/PreviewCursor.scss
+++ b/src/client/views/PreviewCursor.scss
@@ -6,4 +6,5 @@
top: 0;
left:0;
pointer-events: none;
+ opacity: 1;
} \ No newline at end of file
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index eed2cc5da..136a272ab 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -1,4 +1,4 @@
-import { action, observable, runInAction } from 'mobx';
+import { action, observable, runInAction, trace } from 'mobx';
import { observer } from 'mobx-react';
import "normalize.css";
import * as React from 'react';
@@ -7,21 +7,16 @@ import { Docs } from '../documents/Documents';
// import { Transform } from 'prosemirror-transform';
import { Doc } from '../../new_fields/Doc';
import { Transform } from "../util/Transform";
+import { TraceMobx } from '../../new_fields/util';
@observer
export class PreviewCursor extends React.Component<{}> {
- private _prompt = React.createRef<HTMLDivElement>();
static _onKeyPress?: (e: KeyboardEvent) => void;
static _getTransform: () => Transform;
static _addLiveTextDoc: (doc: Doc) => void;
static _addDocument: (doc: Doc) => boolean;
@observable static _clickPoint = [0, 0];
@observable public static Visible = false;
- //when focus is lost, this will remove the preview cursor
- @action onBlur = (): void => {
- PreviewCursor.Visible = false;
- }
-
constructor(props: any) {
super(props);
document.addEventListener("keydown", this.onKeyPress);
@@ -108,6 +103,12 @@ export class PreviewCursor extends React.Component<{}> {
}
}
}
+
+ //when focus is lost, this will remove the preview cursor
+ @action onBlur = (): void => {
+ PreviewCursor.Visible = false;
+ }
+
@action
public static Show(x: number, y: number,
onKeyPress: (e: KeyboardEvent) => void,
@@ -119,18 +120,13 @@ export class PreviewCursor extends React.Component<{}> {
this._addLiveTextDoc = addLiveText;
this._getTransform = getTransform;
this._addDocument = addDocument;
- setTimeout(action(() => this.Visible = true), (1));
+ this.Visible = true;
}
render() {
- if (!PreviewCursor._clickPoint) {
- return (null);
- }
- if (PreviewCursor.Visible && this._prompt.current) {
- this._prompt.current.focus();
- }
- return <div className="previewCursor" id="previewCursor" onBlur={this.onBlur} tabIndex={0} ref={this._prompt}
- style={{ transform: `translate(${PreviewCursor._clickPoint[0]}px, ${PreviewCursor._clickPoint[1]}px)`, opacity: PreviewCursor.Visible ? 1 : 0 }}>
- I
+ return (!PreviewCursor._clickPoint || !PreviewCursor.Visible) ? (null) :
+ <div className="previewCursor" onBlur={this.onBlur} tabIndex={0} ref={e => e && e.focus()}
+ style={{ transform: `translate(${PreviewCursor._clickPoint[0]}px, ${PreviewCursor._clickPoint[1]}px)` }}>
+ I
</div >;
}
} \ No newline at end of file
diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index ba87025c4..0dd4f734c 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -45,7 +45,7 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
this._touchDrag = true;
switch (e.targetTouches.length) {
case 1:
- this.handle1PointerMove(e)
+ this.handle1PointerMove(e);
break;
case 2:
this.handle2PointersMove(e);
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index ba83630a4..4eb9e9d1e 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -14,6 +14,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEdit } from "@fortawesome/free-solid-svg-icons";
import { library } from "@fortawesome/fontawesome-svg-core";
import { MetadataEntryMenu } from "../MetadataEntryMenu";
+import { DocumentView } from "../nodes/DocumentView";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 48d330674..e1d23ddcb 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -6,6 +6,8 @@ import { ScriptField } from "../../../../new_fields/ScriptField";
import { OverlayView, OverlayElementOptions } from "../../OverlayView";
import { emptyFunction } from "../../../../Utils";
import React = require("react");
+import { ObservableMap, runInAction } from "mobx";
+import { Id } from "../../../../new_fields/FieldSymbols";
interface PivotData {
type: string;
@@ -31,8 +33,7 @@ export interface ViewDefResult {
bounds?: ViewDefBounds;
}
-export function computePivotLayout(pivotDoc: Doc, childDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], viewDefsToJSX: (views: any) => ViewDefResult[]) {
- let layoutPoolData: Map<{ layout: Doc, data?: Doc }, any> = new Map();
+export function computePivotLayout(poolData: ObservableMap<string, any>, pivotDoc: Doc, childDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], viewDefsToJSX: (views: any) => ViewDefResult[]) {
const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, 200);
const pivotColumnGroups = new Map<FieldResult<Field>, Doc[]>();
@@ -49,6 +50,8 @@ export function computePivotLayout(pivotDoc: Doc, childDocs: Doc[], childPairs:
const docMap = new Map<Doc, ViewDefBounds>();
const groupNames: PivotData[] = [];
+ const expander = 1.05;
+ const gap = .15;
let x = 0;
pivotColumnGroups.forEach((val, key) => {
let y = 0;
@@ -58,25 +61,31 @@ export function computePivotLayout(pivotDoc: Doc, childDocs: Doc[], childPairs:
text: String(key),
x,
y: pivotAxisWidth + 50,
- width: pivotAxisWidth * 1.25 * numCols,
+ width: pivotAxisWidth * expander * numCols,
height: 100,
fontSize: NumCast(pivotDoc.pivotFontSize, 10)
});
for (const doc of val) {
let layoutDoc = Doc.Layout(doc);
+ let wid = pivotAxisWidth;
+ let hgt = layoutDoc.nativeWidth ? (NumCast(layoutDoc.nativeHeight) / NumCast(layoutDoc.nativeWidth)) * pivotAxisWidth : pivotAxisWidth;
+ if (hgt > pivotAxisWidth) {
+ hgt = pivotAxisWidth;
+ wid = layoutDoc.nativeHeight ? (NumCast(layoutDoc.nativeWidth) / NumCast(layoutDoc.nativeHeight)) * pivotAxisWidth : pivotAxisWidth;
+ }
docMap.set(doc, {
- x: x + xCount * pivotAxisWidth * 1.25,
+ x: x + xCount * pivotAxisWidth * expander + (pivotAxisWidth - wid) / 2,
y: -y,
- width: pivotAxisWidth,
- height: layoutDoc.nativeWidth ? (NumCast(layoutDoc.nativeHeight) / NumCast(layoutDoc.nativeWidth)) * pivotAxisWidth : pivotAxisWidth
+ width: wid,
+ height: hgt
});
xCount++;
if (xCount >= numCols) {
- xCount = 0;
- y += pivotAxisWidth * 1.25;
+ xCount = (pivotAxisWidth - wid) / 2;
+ y += pivotAxisWidth * expander;
}
}
- x += pivotAxisWidth * 1.25 * (numCols + 1);
+ x += pivotAxisWidth * (numCols * expander + gap);
});
childPairs.map(pair => {
@@ -88,9 +97,12 @@ export function computePivotLayout(pivotDoc: Doc, childDocs: Doc[], childPairs:
height: NumCast(pair.layout.height)
};
const pos = docMap.get(pair.layout) || defaultPosition;
- layoutPoolData.set(pair, { transition: "transform 1s", ...pos });
+ let data = poolData.get(pair.layout[Id]);
+ if (!data || pos.x !== data.x || pos.y !== data.y || pos.z !== data.z || pos.width !== data.width || pos.height !== data.height) {
+ runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...pos }));
+ }
});
- return { map: layoutPoolData, elements: viewDefsToJSX(groupNames) };
+ return { elements: viewDefsToJSX(groupNames) };
}
export function AddCustomFreeFormLayout(doc: Doc, dataKey: string): () => void {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 837413842..73b45edc6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -6,7 +6,8 @@ import "./CollectionFreeFormLinkView.scss";
import React = require("react");
import v5 = require("uuid/v5");
import { DocumentType } from "../../../documents/DocumentTypes";
-import { observable, action } from "mobx";
+import { observable, action, reaction, IReactionDisposer } from "mobx";
+import { StrCast, Cast } from "../../../../new_fields/Types";
export interface CollectionFreeFormLinkViewProps {
A: DocumentView;
@@ -16,33 +17,57 @@ export interface CollectionFreeFormLinkViewProps {
@observer
export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFormLinkViewProps> {
- @observable _alive: number = 0;
@observable _opacity: number = 1;
+ @observable _update: number = 0;
+ _anchorDisposer: IReactionDisposer | undefined;
@action
componentDidMount() {
- this._alive = 1;
- setTimeout(this.rerender, 50);
- setTimeout(action(() => this._opacity = 0.05), 50);
+ setTimeout(action(() => this._opacity = 0.05), 750);
+ this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform()],
+ () => {
+ let acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
+ let bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
+ let adiv = (acont.length ? acont[0] : this.props.A.ContentDiv!);
+ let bdiv = (bcont.length ? bcont[0] : this.props.B.ContentDiv!);
+ let a = adiv.getBoundingClientRect();
+ let b = bdiv.getBoundingClientRect();
+ let abounds = adiv.parentElement!.getBoundingClientRect();
+ let bbounds = bdiv.parentElement!.getBoundingClientRect();
+ let apt = Utils.closestPtBetweenRectangles(abounds.left, abounds.top, abounds.width, abounds.height,
+ bbounds.left, bbounds.top, bbounds.width, bbounds.height,
+ a.left + a.width / 2, a.top + a.height / 2);
+ let bpt = Utils.closestPtBetweenRectangles(bbounds.left, bbounds.top, bbounds.width, bbounds.height,
+ abounds.left, abounds.top, abounds.width, abounds.height,
+ apt.point.x, apt.point.y);
+ let afield = StrCast(this.props.A.props.Document[StrCast(this.props.A.props.layoutKey, "layout")]).indexOf("anchor1") === -1 ? "anchor2" : "anchor1";
+ let bfield = afield === "anchor1" ? "anchor2" : "anchor1";
+ this.props.A.props.Document[afield + "_x"] = (apt.point.x - abounds.left) / abounds.width * 100;
+ this.props.A.props.Document[afield + "_y"] = (apt.point.y - abounds.top) / abounds.height * 100;
+ this.props.A.props.Document[bfield + "_x"] = (bpt.point.x - bbounds.left) / bbounds.width * 100;
+ this.props.A.props.Document[bfield + "_y"] = (bpt.point.y - bbounds.top) / bbounds.height * 100;
+ this._update++;
+ }
+ , { fireImmediately: true });
}
@action
componentWillUnmount() {
- this._alive = 0;
+ this._anchorDisposer?.();
}
- rerender = action(() => {
- if (this._alive) {
- setTimeout(this.rerender, 50);
- this._alive++;
- }
- });
render() {
- let y = this._alive;
+ let y = this._update;
let acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
let bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
let a = (acont.length ? acont[0] : this.props.A.ContentDiv!).getBoundingClientRect();
let b = (bcont.length ? bcont[0] : this.props.B.ContentDiv!).getBoundingClientRect();
- let pt1 = Utils.getNearestPointInPerimeter(a.left, a.top, a.width, a.height, b.left + b.width / 2, b.top + b.height / 2);
- let pt2 = Utils.getNearestPointInPerimeter(b.left, b.top, b.width, b.height, a.left + a.width / 2, a.top + a.height / 2);
+ let apt = Utils.closestPtBetweenRectangles(a.left, a.top, a.width, a.height,
+ b.left, b.top, b.width, b.height,
+ a.left + a.width / 2, a.top + a.height / 2);
+ let bpt = Utils.closestPtBetweenRectangles(b.left, b.top, b.width, b.height,
+ a.left, a.top, a.width, a.height,
+ apt.point.x, apt.point.y);
+ let pt1 = [apt.point.x, apt.point.y];
+ let pt2 = [bpt.point.x, bpt.point.y];
return (<line key="linkLine" className="collectionfreeformlinkview-linkLine"
style={{ opacity: this._opacity }}
x1={`${pt1[0]}`} y1={`${pt1[1]}`}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index d2731703f..070d4aa65 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -1,5 +1,6 @@
@import "../../globalCssVariables";
+.collectionfreeformview-none,
.collectionfreeformview-ease {
position: inherit;
top: 0;
@@ -7,16 +8,14 @@
width: 100%;
height: 100%;
transform-origin: left top;
+ border-radius: inherit;
+}
+
+.collectionfreeformview-ease {
transition: transform 1s;
}
.collectionfreeformview-none {
- position: inherit;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- transform-origin: left top;
touch-action: none;
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8791a256c..9bbaa20e7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -40,6 +40,7 @@ import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
import { computedFn, keepAlive } from "mobx-utils";
+import { TraceMobx } from "../../../../new_fields/util";
library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
@@ -73,7 +74,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
private _layoutPoolData = new ObservableMap<string, any>();
public get displayName() { return "CollectionFreeFormView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
- @observable _layoutElements: ViewDefResult[] = [];
+ @observable.shallow _layoutElements: ViewDefResult[] = []; // shallow because some layout items (eg pivot labels) are just generated 'divs' and can't be frozen as observables
@observable _clusterSets: (Doc[])[] = [];
@computed get fitToContent() { return (this.props.fitToBox || this.Document.fitToBox) && !this.isAnnotationOverlay; }
@@ -488,9 +489,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
let [x, y] = this.getTransform().transformPoint(pointX, pointY);
let localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y);
- let safeScale = Math.min(Math.max(0.15, localTransform.Scale), 40);
- this.props.Document.scale = Math.abs(safeScale);
- this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale);
+ if (localTransform.Scale >= 0.15) {
+ let safeScale = Math.min(Math.max(0.15, localTransform.Scale), 40);
+ this.props.Document.scale = Math.abs(safeScale);
+ this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale);
+ }
}
@action
@@ -619,12 +622,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
getCalculatedPositions(params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, z?: number, width?: number, height?: number, transition?: string, state?: any } {
- const script = this.Document.arrangeScript;
- const result = script && script.script.run(params, console.log);
- const layoutDoc = Doc.Layout(params.doc);
- if (result && result.success) {
+ const result = this.Document.arrangeScript?.script.run(params, console.log);
+ if (result?.success) {
return { ...result, transition: "transform 1s" };
}
+ const layoutDoc = Doc.Layout(params.doc);
return { x: Cast(params.doc.x, "number"), y: Cast(params.doc.y, "number"), z: Cast(params.doc.z, "number"), width: Cast(layoutDoc.width, "number"), height: Cast(layoutDoc.height, "number") };
}
@@ -651,25 +653,25 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
}
- childDataProvider = computedFn((doc: Doc) => this._layoutPoolData.get(doc[Id]));
+ childDataProvider = computedFn(function childDataProvider(doc: Doc) { return (this as any)._layoutPoolData.get(doc[Id]); }.bind(this));
- get doPivotLayout() {
- return computePivotLayout(this.props.Document, this.childDocs,
+ doPivotLayout(poolData: ObservableMap<string, any>) {
+ return computePivotLayout(poolData, this.props.Document, this.childDocs,
this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)), this.viewDefsToJSX);
}
- get doFreeformLayout() {
+ doFreeformLayout(poolData: ObservableMap<string, any>) {
let layoutDocs = this.childLayoutPairs.map(pair => pair.layout);
const initResult = this.Document.arrangeInit && this.Document.arrangeInit.script.run({ docs: layoutDocs, collection: this.Document }, console.log);
let state = initResult && initResult.success ? initResult.result.scriptState : undefined;
let elements = initResult && initResult.success ? this.viewDefsToJSX(initResult.result.views) : [];
this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => {
+ const data = poolData.get(pair.layout[Id]);
const pos = this.getCalculatedPositions({ doc: pair.layout, index: i, collection: this.Document, docs: layoutDocs, state });
state = pos.state === undefined ? state : pos.state;
- let data = this._layoutPoolData.get(pair.layout[Id]);
if (!data || pos.x !== data.x || pos.y !== data.y || pos.z !== data.z || pos.width !== data.width || pos.height !== data.height || pos.transition !== data.transition) {
- runInAction(() => this._layoutPoolData.set(pair.layout[Id], pos));
+ runInAction(() => poolData.set(pair.layout[Id], pos));
}
});
return { elements: elements };
@@ -678,8 +680,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
get doLayoutComputation() {
let computedElementData: { elements: ViewDefResult[] };
switch (this.Document.freeformLayoutEngine) {
- case "pivot": computedElementData = this.doPivotLayout; break;
- default: computedElementData = this.doFreeformLayout; break;
+ case "pivot": computedElementData = this.doPivotLayout(this._layoutPoolData); break;
+ default: computedElementData = this.doFreeformLayout(this._layoutPoolData); break;
}
this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).forEach(pair =>
computedElementData.elements.push({
@@ -693,14 +695,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
componentDidMount() {
- this._layoutComputeReaction = reaction(() => this.doLayoutComputation,
+ this._layoutComputeReaction = reaction(() => { TraceMobx(); return this.doLayoutComputation; },
action((computation: { elements: ViewDefResult[] }) => computation && (this._layoutElements = computation.elements)),
- { fireImmediately: true });
+ { fireImmediately: true, name: "doLayout" });
}
componentWillUnmount() {
this._layoutComputeReaction && this._layoutComputeReaction();
}
- @computed.struct get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
+ @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
elementFunc = () => this._layoutElements;
@action
@@ -843,7 +845,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
return eles;
}
render() {
- // trace();
+ TraceMobx();
// update the actual dimensions of the collection so that they can inquired (e.g., by a minimap)
// this.Document.fitX = this.contentBounds && this.contentBounds.x;
// this.Document.fitY = this.contentBounds && this.contentBounds.y;
@@ -873,9 +875,8 @@ interface CollectionFreeFormOverlayViewProps {
@observer
class CollectionFreeFormOverlayView extends React.Component<CollectionFreeFormOverlayViewProps>{
- @computed.struct get overlayViews() { return this.props.elements().filter(ele => ele.bounds && ele.bounds.z).map(ele => ele.ele); }
render() {
- return this.overlayViews;
+ return this.props.elements().filter(ele => ele.bounds && ele.bounds.z).map(ele => ele.ele);
}
}
@@ -898,7 +899,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
const panx = -this.props.panX();
const pany = -this.props.panY();
const zoom = this.props.zoomScaling();
- return <div className={freeformclass} style={{ borderRadius: "inherit", transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)` }}>
+ return <div className={freeformclass} style={{ transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)` }}>
{this.props.children()}
</div>;
}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index bcff91f4b..c85b59488 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -10,6 +10,7 @@ import "./CollectionFreeFormDocumentView.scss";
import { DocumentView, DocumentViewProps } from "./DocumentView";
import React = require("react");
import { PositionDocument } from "../../../new_fields/documentSchemas";
+import { TraceMobx } from "../../../new_fields/util";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
dataProvider?: (doc: Doc) => { x: number, y: number, width: number, height: number, z: number, transition?: string } | undefined;
@@ -56,11 +57,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
this._disposer && this._disposer();
}
componentDidMount() {
- this._disposer = reaction(() => [this.props.Document.animateToPos, this.props.Document.isAnimating],
- () => {
- const target = this.props.Document.animateToPos ? Array.from(Cast(this.props.Document.animateToPos, listSpec("number"))!) : undefined;
- this._animPos = !target ? undefined : target[2] ? [NumCast(this.layoutDoc.x), NumCast(this.layoutDoc.y)] : this.props.ScreenToLocalTransform().transformPoint(target[0], target[1]);
- }, { fireImmediately: true });
+ this._disposer = reaction(() => this.props.Document.animateToPos ? Array.from(Cast(this.props.Document.animateToPos, listSpec("number"))!) : undefined,
+ target => this._animPos = !target ? undefined : target[2] ? [NumCast(this.layoutDoc.x), NumCast(this.layoutDoc.y)] : this.props.ScreenToLocalTransform().transformPoint(target[0], target[1]),
+ { fireImmediately: true });
}
contentScaling = () => this.nativeWidth > 0 && !this.props.Document.ignoreAspect ? this.width / this.nativeWidth : 1;
@@ -88,7 +87,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
finalPanelHeight = () => this.dataProvider ? this.dataProvider.height : this.panelHeight();
render() {
- // trace();
+ TraceMobx();
return <div className="collectionFreeFormDocumentView-container"
style={{
boxShadow:
@@ -99,7 +98,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
StrCast(this.layoutDoc.boxShadow, ""),
borderRadius: this.borderRounding(),
transform: this.transform,
- transition: this.Document.isAnimating !== undefined ? ".5s ease-in" : this.props.transition ? this.props.transition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.transition),
+ transition: this.Document.isAnimating ? ".5s ease-in" : this.props.transition ? this.props.transition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.transition),
width: this.width,
height: this.height,
zIndex: this.Document.zIndex || 0,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index becb7bdfe..467fd4b32 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -41,6 +41,9 @@ import "./DocumentView.scss";
import { FormattedTextBox } from './FormattedTextBox';
import React = require("react");
import { InteractionUtils } from '../../util/InteractionUtils';
+import { InkingControl } from '../InkingControl';
+import { InkTool } from '../../../new_fields/InkField';
+import { TraceMobx } from '../../../new_fields/util';
library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
@@ -540,7 +543,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@computed get finalLayoutKey() { return this.props.layoutKey || "layout"; }
childScaling = () => (this.layoutDoc.fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
@computed get contents() {
- // trace();
+ TraceMobx();
return (<DocumentContentsView ContainingCollectionView={this.props.ContainingCollectionView}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}
Document={this.props.Document}
@@ -584,7 +587,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
@computed get innards() {
- // trace();
+ TraceMobx();
const showOverlays = this.props.showOverlays ? this.props.showOverlays(this.Document) : undefined;
const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.getLayoutPropStr("showTitle");
const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.getLayoutPropStr("showCaption");
@@ -614,9 +617,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
/>
</div>);
return <>
- {this.Document.links && DocListCast(this.Document.links).filter((d) => !DocListCast(this.layoutDoc.hiddenLinks).some(hidden => Doc.AreProtosEqual(hidden, d))).filter(this.isNonTemporalLink).map((d, i) =>
- <div className="documentView-docuLinkWrapper" key={`${d[Id]}`} style={{ transform: `scale(${this.layoutDoc.fitWidth ? 1 : 1 / 1})` }}>
- <DocumentView {...this.props} ContentScaling={returnOne} Document={d} layoutKey={this.linkEndpoint(d)} backgroundColor={returnTransparent} removeDocument={undoBatch(doc => Doc.AddDocToList(this.layoutDoc, "hiddenLinks", doc))} />
+ {this.Document.links && DocListCast(this.Document.links).filter(d => !d.hidden).filter(this.isNonTemporalLink).map((d, i) =>
+ <div className="documentView-docuLinkWrapper" key={`${d[Id]}`}>
+ <DocumentView {...this.props} ContentScaling={returnOne} Document={d} layoutKey={this.linkEndpoint(d)} backgroundColor={returnTransparent} removeDocument={undoBatch(doc => doc.hidden = true)} />
</div>)}
{!showTitle && !showCaption ?
this.Document.searchFields ?
@@ -639,7 +642,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
</>;
}
@computed get ignorePointerEvents() {
- return this.Document.isBackground && !this.isSelected();
+ return (this.Document.isBackground && !this.isSelected()) || (this.Document.type === DocumentType.INK && InkingControl.Instance.selectedTool !== InkTool.None);
}
render() {
@@ -665,9 +668,16 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc.viewType !== CollectionViewType.Linear;
return <div className={`documentView-node${this.topMost ? "-topmost" : ""}`} ref={this._mainCont}
onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
- onPointerEnter={e => Doc.BrushDoc(this.props.Document)} onPointerLeave={e => Doc.UnBrushDoc(this.props.Document)}
+ onPointerEnter={e => {
+ console.log("Brush" + this.props.Document.title);
+ Doc.BrushDoc(this.props.Document);
+ }} onPointerLeave={e => {
+ console.log("UnBrush" + this.props.Document.title);
+ Doc.UnBrushDoc(this.props.Document);
+
+ }}
style={{
- transition: this.Document.isAnimating !== undefined ? ".5s linear" : StrCast(this.Document.transition),
+ transition: this.Document.isAnimating ? ".5s linear" : StrCast(this.Document.transition),
pointerEvents: this.ignorePointerEvents ? "none" : "all",
color: StrCast(this.Document.color),
outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index 9a5de836f..960b55e3e 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -43,7 +43,7 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
background: StrCast(referenceLayout.backgroundColor),
boxShadow: this.props.Document.ischecked ? `4px 4px 12px black` : undefined
}}>
- <FontAwesomeIcon className="fontIconBox-icon" icon={this.Document.icon as any} color={this._foregroundColor} size="md" />
+ <FontAwesomeIcon className="fontIconBox-icon" icon={this.Document.icon as any} color={this._foregroundColor} size="sm" />
</button>;
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 269a3ca68..77cdd3d42 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -27,6 +27,8 @@
pointer-events: all;
overflow-y: auto;
max-height: 100%;
+ display: flex;
+ flex-direction: row;
.formattedTextBox-dictation {
height: 20px;
@@ -48,10 +50,28 @@
width: 100%;
height: 100%;
}
-.formattedTextBox-sidebar,.formattedTextBox-sidebar-inking {
- border-left: solid 1px black;
+.formattedTextBox-sidebar-handle {
+ position: absolute;
+ top: calc(50% - 17.5px);
+ width: 10px;
+ height: 35px;
+ background: lightgray;
+ border-radius: 20px;
+}
+.formattedTextBox-cont > .formattedTextBox-sidebar-handle {
+ right: 0;
+ left: unset;
+}
+.formattedTextBox-sidebar, .formattedTextBox-sidebar-inking {
+ border-left: dashed 1px black;
height: 100%;
display: inline-block;
+ position: absolute;
+ right: 0;
+ > .formattedTextBox-sidebar-handle {
+ right:unset;
+ left:-5;
+ }
}
.formattedTextBox-sidebar-inking {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 2f9e8d5f4..9910c9ecd 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -47,6 +47,7 @@ import { documentSchema } from '../../../new_fields/documentSchemas';
import { AudioBox } from './AudioBox';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { InkTool } from '../../../new_fields/InkField';
+import { TraceMobx } from '../../../new_fields/util';
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -358,9 +359,11 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
}
+ toggleSidebar = () => this.props.Document.sidebarWidthPercent = StrCast(this.props.Document.sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%";
+
specificContextMenu = (e: React.MouseEvent): void => {
let funcs: ContextMenuProps[] = [];
- funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document.sidebarWidthPercent = StrCast(this.props.Document.sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%"; }, icon: "expand-arrows-alt" });
+ funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.toggleSidebar(); }, icon: "expand-arrows-alt" });
funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" });
["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option =>
funcs.push({
@@ -997,13 +1000,16 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
if (!this._undoTyping) {
this._undoTyping = UndoManager.StartBatch("undoTyping");
}
- if (this._recording) { this.stopDictation(true); setTimeout(() => this.recordDictation(), 250); }
+ if (this._recording) {
+ this.stopDictation(true);
+ setTimeout(() => this.recordDictation(), 250);
+ }
}
@action
tryUpdateHeight() {
- let scrollHeight = this._ref.current ? this._ref.current.scrollHeight : 0;
- if (!this.layoutDoc.isAnimating && this.layoutDoc.autoHeight && scrollHeight !== 0 &&
+ const scrollHeight = this._ref.current?.scrollHeight;
+ if (!this.layoutDoc.animateToPos && this.layoutDoc.autoHeight && scrollHeight &&
getComputedStyle(this._ref.current!.parentElement!).top === "0px") { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
let nh = this.Document.isTemplateField ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
let dh = NumCast(this.layoutDoc.height, 0);
@@ -1016,7 +1022,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
@computed get sidebarWidth() { return Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); }
@computed get annotationsKey() { return "annotations"; }
render() {
- // trace();
+ TraceMobx();
let rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
let interactive = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground;
if (this.props.isSelected()) {
@@ -1050,29 +1056,33 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
<div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }}>
<div className={`formattedTextBox-inner${rounded}`} style={{ whiteSpace: "pre-wrap", pointerEvents: ((this.Document.isButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined }} ref={this.createDropTarget} />
</div>
- {this.sidebarWidthPercent === "0%" ? (null) : <div className={"formattedTextBox-sidebar" + (InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : "")} style={{ width: `${this.sidebarWidthPercent}` }}>
- <CollectionFreeFormView {...this.props}
- PanelHeight={() => this.props.PanelHeight()}
- PanelWidth={() => this.sidebarWidth}
- annotationsKey={this.annotationsKey}
- isAnnotationOverlay={true}
- focus={this.props.focus}
- isSelected={this.props.isSelected}
- select={emptyFunction}
- active={this.annotationsActive}
- ContentScaling={returnOne}
- whenActiveChanged={this.whenActiveChanged}
- removeDocument={this.removeDocument}
- moveDocument={this.moveDocument}
- addDocument={this.addDocument}
- CollectionView={undefined}
- ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)}
- ruleProvider={undefined}
- renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}
- chromeCollapsed={true}>
- </CollectionFreeFormView>
- </div>}
+ {this.sidebarWidthPercent === "0%" ?
+ <div className="formattedTextBox-sidebar-handle" onPointerDown={e => e.stopPropagation()} onClick={e => this.toggleSidebar()} /> :
+ <div className={"formattedTextBox-sidebar" + (InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : "")}
+ style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${StrCast(this.extensionDoc?.backgroundColor, "transparent")}` }}>
+ <CollectionFreeFormView {...this.props}
+ PanelHeight={() => this.props.PanelHeight()}
+ PanelWidth={() => this.sidebarWidth}
+ annotationsKey={this.annotationsKey}
+ isAnnotationOverlay={true}
+ focus={this.props.focus}
+ isSelected={this.props.isSelected}
+ select={emptyFunction}
+ active={this.annotationsActive}
+ ContentScaling={returnOne}
+ whenActiveChanged={this.whenActiveChanged}
+ removeDocument={this.removeDocument}
+ moveDocument={this.moveDocument}
+ addDocument={this.addDocument}
+ CollectionView={undefined}
+ ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)}
+ ruleProvider={undefined}
+ renderDepth={this.props.renderDepth + 1}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+ chromeCollapsed={true}>
+ </CollectionFreeFormView>
+ <div className="formattedTextBox-sidebar-handle" onPointerDown={e => e.stopPropagation()} onClick={e => this.toggleSidebar()} />
+ </div>}
<div className="formattedTextBox-dictation"
onClick={e => {
this._recording ? this.stopDictation(true) : this.recordDictation();
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index dcecbdc6e..ba4ef8879 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -16,6 +16,7 @@
width:100%;
height:100%;
position: absolute;
+ transform-origin: top left;
}
.imageBox-cont-interactive {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 86dc4fccc..a57059f77 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -26,6 +26,7 @@ import React = require("react");
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { documentSchema } from '../../../new_fields/documentSchemas';
import { Id } from '../../../new_fields/FieldSymbols';
+import { TraceMobx } from '../../../new_fields/util';
var requestImageSize = require('../../util/request-image-size');
var path = require('path');
const { Howl } = require('howler');
@@ -267,7 +268,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
}
@computed get content() {
- // trace();
+ TraceMobx();
const extensionDoc = this.extensionDoc;
if (!extensionDoc) return (null);
// let transform = this.props.ScreenToLocalTransform().inverse();
@@ -290,7 +291,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
if (field instanceof ImageField) paths = [this.choosePath(field.url)];
paths.push(...altpaths);
// }
- let interactive = InkingControl.Instance.selectedTool || this.Document.isBackground ? "" : "-interactive";
+ let interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive";
let rotation = NumCast(this.Document.rotation, 0);
let aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1;
let shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0;
@@ -333,7 +334,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
contentFunc = () => [this.content];
render() {
return (<div className={"imageBox-container"} onContextMenu={this.specificContextMenu}
- style={{ transformOrigin: "top left", transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
+ style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
<CollectionFreeFormView {...this.props}
PanelHeight={this.props.PanelHeight}
PanelWidth={this.props.PanelWidth}
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 5a5f784a1..46af63a7d 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -1,3 +1,11 @@
+.pdfBox-ui {
+ position: absolute;
+ width: 100%;
+ height:100%;
+ z-index: 1;
+ pointer-events: none;
+}
+
.pdfBox-cont,
.pdfBox-cont-interactive {
display: inline-block;
@@ -134,14 +142,13 @@
.pdfBox-overlayCont {
position: absolute;
- width: 100%;
- height: 40px;
+ width: calc(100% - 40px);
+ height: 30px;
background: #121721;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
- padding: 20px;
overflow: hidden;
transition: left .5s;
pointer-events: all;
@@ -171,30 +178,24 @@
border-right: 15px solid #121721;
transition: all 0.5s;
}
+}
- .pdfBox-overlayButton-iconCont,
- .pdfBox-nextIcon,
- .pdfBox-prevIcon {
- background: #121721;
- height: 30px;
- width: 70px;
- display: flex;
- justify-content: center;
- align-items: center;
- margin-left: -2px;
- border-radius: 3px;
- position: absolute;
- pointer-events: all;
- }
+.pdfBox-overlayButton-iconCont,
+.pdfBox-nextIcon,
+.pdfBox-prevIcon {
+ padding: 0;
+ background: #121721;
+ height: 30px;
+ width: 25px;
+ display: inline-block;
+ position: relative;
+ justify-content: center;
+ align-items: center;
+ margin-left: -2px;
+ border-radius: 3px;
+ pointer-events: all;
}
.pdfBox-overlayButton:hover {
background: none;
}
-
-.pdfBox-nextIcon {
- left: 20; top: 5; height: 30px; position: absolute;
-}
-.pdfBox-prevIcon {
- left: 50; top: 5; height: 30px; position: absolute;
-}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index e7d8ac46c..23512543a 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -21,7 +21,6 @@ import { pageSchema } from "./ImageBox";
import "./PDFBox.scss";
import React = require("react");
import { documentSchema } from '../../../new_fields/documentSchemas';
-import { SelectionManager } from '../../util/SelectionManager';
type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>;
const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema);
@@ -119,17 +118,17 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
settingsPanel() {
let pageBtns = <>
<button className="pdfBox-overlayButton-iconCont" key="back" title="Page Back"
- onPointerDown={e => e.stopPropagation()} onClick={this.backPage} style={{ left: 50, top: 5 }}>
+ onPointerDown={e => e.stopPropagation()} onClick={e => this.backPage()} style={{ left: 45, top: 5 }}>
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-left"} size="sm" />
</button>
<button className="pdfBox-overlayButton-iconCont" key="fwd" title="Page Forward"
- onPointerDown={e => e.stopPropagation()} onClick={this.forwardPage} style={{ left: 80, top: 5 }}>
+ onPointerDown={e => e.stopPropagation()} onClick={e => this.forwardPage()} style={{ left: 45, top: 5 }}>
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-right"} size="sm" />
</button>
</>;
return !this.active() ? (null) :
(<div className="pdfBox-ui" onKeyDown={e => e.keyCode === KeyCodes.BACKSPACE || e.keyCode === KeyCodes.DELETE ? e.stopPropagation() : true}
- onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "none", position: "absolute", width: "100%", height: "100%", zIndex: 1, pointerEvents: "none" }}>
+ onPointerDown={e => e.stopPropagation()} style={{ display: this.active() ? "flex" : "none" }}>
<div className="pdfBox-overlayCont" key="cont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}>
<button className="pdfBox-overlayButton" title="Open Search Bar" />
<input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged} onKeyDown={e => e.keyCode === KeyCodes.ENTER && this.search(this._searchString, !e.shiftKey)} />
@@ -142,14 +141,14 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
<FontAwesomeIcon style={{ color: "white" }} icon={"arrow-down"} size="sm" />
</button>
</div>
- <button className="pdfBox-overlayButton" key="search" onClick={action(() => this._searching = !this._searching)} title="Open Search Bar" style={{ bottom: 8, right: 0 }}>
+ <button className="pdfBox-overlayButton" key="search" onClick={action(() => this._searching = !this._searching)} title="Open Search Bar" style={{ bottom: 0, right: 0 }}>
<div className="pdfBox-overlayButton-arrow" onPointerDown={(e) => e.stopPropagation()}></div>
<div className="pdfBox-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
<FontAwesomeIcon style={{ color: "white", padding: 5 }} icon={this._searching ? "times" : "search"} size="3x" /></div>
</button>
<input value={`${(this.Document.curPage || 1)}`}
onChange={e => this.gotoPage(Number(e.currentTarget.value))}
- style={{ left: 20, top: 5, height: "30px", width: "30px", position: "absolute", pointerEvents: "all" }}
+ style={{ left: 5, top: 5, height: "30px", width: "30px", position: "absolute", pointerEvents: "all" }}
onClick={action(() => this._pageControls = !this._pageControls)} />
{this._pageControls ? pageBtns : (null)}
<div className="pdfBox-settingsCont" key="settings" onPointerDown={(e) => e.stopPropagation()}>
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index 5829c1bd9..0a4c650a8 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -1,5 +1,6 @@
.videoBox-container {
pointer-events: all;
+ transform-origin: top left;
.inkingCanvas-paths-markers {
opacity : 0.4; // we shouldn't have to do this, but since chrome crawls to a halt with z-index unset in videoBox-content, this is a workaround
}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 1d1972841..0b0baeeb5 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -335,7 +335,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content];
render() {
return (<div className={"videoBox-container"} onContextMenu={this.specificContextMenu}
- style={{ transformOrigin: "top left", transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
+ style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
<CollectionFreeFormView {...this.props}
PanelHeight={this.props.PanelHeight}
PanelWidth={this.props.PanelWidth}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index de764346f..f1c500391 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -29,6 +29,7 @@ import { documentSchema } from "../../../new_fields/documentSchemas";
import { DocumentDecorations } from "../DocumentDecorations";
import { InkingControl } from "../InkingControl";
import { InkTool } from "../../../new_fields/InkField";
+import { TraceMobx } from "../../../new_fields/util";
const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
const pdfjsLib = require("pdfjs-dist");
@@ -620,7 +621,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
}
@computed get annotationLayer() {
- // trace();
+ TraceMobx();
return <div className="pdfViewer-annotationLayer" style={{ height: (this.Document.nativeHeight || 0), transform: `scale(${this._zoomed})` }} ref={this._annotationLayer}>
{this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) =>
<Annotation {...this.props} focus={this.props.focus} extensionDoc={this.extensionDoc!} anno={anno} key={`${anno[Id]}-annotation`} />)}
@@ -672,14 +673,15 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
marqueeing = () => this._marqueeing;
visibleHeight = () => this.props.PanelHeight() / this.props.ContentScaling() * 72 / 96;
contentZoom = () => this._zoomed;
+ @computed get contentScaling() { return this.props.ContentScaling(); }
render() {
- // trace();
+ TraceMobx();
return !this.extensionDoc ? (null) :
<div className={"pdfViewer-viewer" + (this._zoomed !== 1 ? "-zoomed" : "")} ref={this._mainCont}
style={{
- width: !this.props.Document.fitWidth ? NumCast(this.props.Document.nativeWidth) : `${100 / this.props.ContentScaling()}%`,
- height: !this.props.Document.fitWidth ? NumCast(this.props.Document.nativeHeight) : `${100 / this.props.ContentScaling()}%`,
- transform: `scale(${this.props.ContentScaling()})`
+ width: !this.props.Document.fitWidth ? NumCast(this.props.Document.nativeWidth) : `${100 / this.contentScaling}%`,
+ height: !this.props.Document.fitWidth ? NumCast(this.props.Document.nativeHeight) : `${100 / this.contentScaling}%`,
+ transform: `scale(${this.contentScaling})`
}} onScroll={this.onScroll} onWheel={this.onZoomWheel} onPointerDown={this.onPointerDown} onClick={this.onClick}>
{this.pdfViewerDiv}
{this.overlayLayer}
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 7592cdaa3..4c2f061a6 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -41,7 +41,7 @@ export const documentSchema = createSchema({
showTitle: "string", // whether an editable title banner is displayed at tht top of the document
isButton: "boolean", // whether document functions as a button (overiding native interactions of its content)
ignoreClick: "boolean", // whether documents ignores input clicks (but does not ignore manipulation and other events)
- isAnimating: "boolean", // whether the document is in the midst of animating between two layouts (used by icons to de/iconify documents).
+ isAnimating: "string", // whether the document is in the midst of animating between two layouts (used by icons to de/iconify documents). value is undefined|"min"|"max"
animateToDimensions: listSpec("number"), // layout information about the target rectangle a document is animating towards
scrollToLinkID: "string", // id of link being traversed. allows this doc to scroll/highlight/etc its link anchor. scrollToLinkID should be set to undefined by this doc after it sets up its scroll,etc.
strokeWidth: "number",
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 04194509c..4147be278 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -4,7 +4,7 @@ import { SerializationHelper } from "../client/util/SerializationHelper";
import { ProxyField } from "./Proxy";
import { RefField } from "./RefField";
import { ObjectField } from "./ObjectField";
-import { action } from "mobx";
+import { action, trace } from "mobx";
import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols";
import { DocServer } from "../client/DocServer";
@@ -12,6 +12,10 @@ function _readOnlySetter(): never {
throw new Error("Documents can't be modified in read-only mode");
}
+export function TraceMobx() {
+ //trace();
+}
+
export interface GetterResult {
value: FieldResult;
shouldReturn?: boolean;