aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx183
-rw-r--r--src/client/views/nodes/DocumentView.tsx232
-rw-r--r--src/client/views/nodes/FieldView.tsx7
-rw-r--r--src/client/views/nodes/FormattedTextBox.scss15
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx58
-rw-r--r--src/client/views/nodes/ImageBox.scss4
-rw-r--r--src/client/views/nodes/ImageBox.tsx9
-rw-r--r--src/client/views/nodes/KeyValueBox.scss1
-rw-r--r--src/client/views/nodes/KeyValuePair.scss1
-rw-r--r--src/client/views/nodes/PDFBox.scss18
-rw-r--r--src/client/views/nodes/PDFBox.tsx249
-rw-r--r--src/client/views/nodes/Sticky.tsx83
-rw-r--r--src/client/views/nodes/VideoBox.tsx20
-rw-r--r--src/client/views/nodes/WebBox.scss17
-rw-r--r--src/client/views/nodes/WebBox.tsx6
15 files changed, 365 insertions, 538 deletions
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 12e5bdf1f..a3a82036d 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,12 +1,17 @@
-import { computed, trace } from "mobx";
+import { computed, trace, action } from "mobx";
import { observer } from "mobx-react";
import { KeyStore } from "../../../fields/KeyStore";
import { NumberField } from "../../../fields/NumberField";
+import { Document } from "../../../fields/Document";
import { Transform } from "../../util/Transform";
import { DocumentView, DocumentViewProps } from "./DocumentView";
import "./DocumentView.scss";
import React = require("react");
-import { OmitKeys } from "../../../Utils";
+import { OmitKeys, Utils } from "../../../Utils";
+import { SelectionManager } from "../../util/SelectionManager";
+import { ListField } from "../../../fields/ListField";
+import { BooleanField } from "../../../fields/BooleanField";
+import { matchedData } from "express-validator/filter";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
}
@@ -14,55 +19,48 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
@observer
export class CollectionFreeFormDocumentView extends React.Component<CollectionFreeFormDocumentViewProps> {
private _mainCont = React.createRef<HTMLDivElement>();
+ private _downX: number = 0;
+ private _downY: number = 0;
- @computed
- get transform(): string {
+ @computed get transform() {
return `scale(${this.props.ContentScaling()}, ${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) scale(${this.zoom}, ${this.zoom}) `;
}
-
- @computed get zoom(): number { return 1 / this.props.Document.GetNumber(KeyStore.ZoomBasis, 1); }
- @computed get zIndex(): number { return this.props.Document.GetNumber(KeyStore.ZIndex, 0); }
- @computed get width(): number { return this.props.Document.Width(); }
- @computed get height(): number { return this.props.Document.Height(); }
- @computed get nativeWidth(): number { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
- @computed get nativeHeight(): number { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
-
+ @computed get X() { return this.props.Document.GetNumber(KeyStore.X, 0); }
+ @computed get Y() { return this.props.Document.GetNumber(KeyStore.Y, 0); }
+ @computed get zoom() { return 1 / this.props.Document.GetNumber(KeyStore.ZoomBasis, 1); }
+ @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
+ @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
+ @computed get width() { return this.props.Document.Width(); }
+ @computed get height() { return this.props.Document.Height(); }
+ @computed get zIndex() { return this.props.Document.GetNumber(KeyStore.ZIndex, 0); }
set width(w: number) {
this.props.Document.SetData(KeyStore.Width, w, NumberField);
if (this.nativeWidth && this.nativeHeight) {
this.props.Document.SetNumber(KeyStore.Height, this.nativeHeight / this.nativeWidth * w);
}
}
-
set height(h: number) {
this.props.Document.SetData(KeyStore.Height, h, NumberField);
if (this.nativeWidth && this.nativeHeight) {
this.props.Document.SetNumber(KeyStore.Width, this.nativeWidth / this.nativeHeight * h);
}
}
-
set zIndex(h: number) {
this.props.Document.SetData(KeyStore.ZIndex, h, NumberField);
}
- get X() {
- return this.props.Document.GetNumber(KeyStore.X, 0);
- }
- get Y() {
- return this.props.Document.GetNumber(KeyStore.Y, 0);
- }
- getTransform = (): Transform =>
- this.props.ScreenToLocalTransform()
- .translate(-this.X, -this.Y)
- .scale(1 / this.contentScaling()).scale(1 / this.zoom)
-
contentScaling = () => (this.nativeWidth > 0 ? this.width / this.nativeWidth : 1);
panelWidth = () => this.props.PanelWidth();
panelHeight = () => this.props.PanelHeight();
+ toggleMinimized = () => this.toggleIcon();
+ getTransform = (): Transform => this.props.ScreenToLocalTransform()
+ .translate(-this.X, -this.Y)
+ .scale(1 / this.contentScaling()).scale(1 / this.zoom)
@computed
get docView() {
return <DocumentView {...OmitKeys(this.props, ['zoomFade'])}
+ toggleMinimized={this.toggleMinimized}
ContentScaling={this.contentScaling}
ScreenToLocalTransform={this.getTransform}
PanelWidth={this.panelWidth}
@@ -70,30 +68,125 @@ export class CollectionFreeFormDocumentView extends React.Component<CollectionFr
/>;
}
+ animateBetweenIcon(first: boolean, icon: number[], targ: number[], width: number, height: number, stime: number, target: Document, maximizing: boolean) {
+ setTimeout(() => {
+ let now = Date.now();
+ let progress = Math.min(1, (now - stime) / 200);
+ let pval = maximizing ?
+ [icon[0] + (targ[0] - icon[0]) * progress, icon[1] + (targ[1] - icon[1]) * progress] :
+ [targ[0] + (icon[0] - targ[0]) * progress, targ[1] + (icon[1] - targ[1]) * progress];
+ target.SetNumber(KeyStore.Width, maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress);
+ target.SetNumber(KeyStore.Height, maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress);
+ target.SetNumber(KeyStore.X, pval[0]);
+ target.SetNumber(KeyStore.Y, pval[1]);
+ if (first) {
+ target.SetBoolean(KeyStore.IsMinimized, false);
+ }
+ if (now < stime + 200) {
+ this.animateBetweenIcon(false, icon, targ, width, height, stime, target, maximizing);
+ }
+ else {
+ if (!maximizing) {
+ target.SetBoolean(KeyStore.IsMinimized, true);
+ target.SetNumber(KeyStore.X, targ[0]);
+ target.SetNumber(KeyStore.Y, targ[1]);
+ target.SetNumber(KeyStore.Width, width);
+ target.SetNumber(KeyStore.Height, height);
+ }
+ (target as any).isIconAnimating = false;
+ }
+ },
+ 2);
+ }
+ @action
+ public toggleIcon = async (): Promise<void> => {
+ SelectionManager.DeselectAll();
+ let isMinimized: boolean | undefined;
+ let minimizedDocSet = await this.props.Document.GetTAsync(KeyStore.LinkTags, ListField);
+ if (!minimizedDocSet) return;
+ minimizedDocSet.Data.map(async minimizedDoc => {
+ if (minimizedDoc instanceof Document) {
+ this.props.addDocument && this.props.addDocument(minimizedDoc, false);
+ let maximizedDoc = await minimizedDoc.GetTAsync(KeyStore.MaximizedDoc, Document);
+ if (maximizedDoc instanceof Document && !(maximizedDoc as any).isIconAnimating) {
+ (maximizedDoc as any).isIconAnimating = true;
+ if (isMinimized === undefined) {
+ let maximizedDocMinimizedState = await maximizedDoc.GetTAsync(KeyStore.IsMinimized, BooleanField);
+ isMinimized = (maximizedDocMinimizedState && maximizedDocMinimizedState.Data) ? true : false;
+ }
+ let minx = await minimizedDoc.GetTAsync(KeyStore.X, NumberField);
+ let miny = await minimizedDoc.GetTAsync(KeyStore.Y, NumberField);
+ let maxx = await maximizedDoc.GetTAsync(KeyStore.X, NumberField);
+ let maxy = await maximizedDoc.GetTAsync(KeyStore.Y, NumberField);
+ let maxw = await maximizedDoc.GetTAsync(KeyStore.Width, NumberField);
+ let maxh = await maximizedDoc.GetTAsync(KeyStore.Height, NumberField);
+ if (minx !== undefined && miny !== undefined && maxx !== undefined && maxy !== undefined &&
+ maxw !== undefined && maxh !== undefined)
+ this.animateBetweenIcon(
+ true,
+ [minx.Data, miny.Data], [maxx.Data, maxy.Data], maxw.Data, maxh.Data,
+ Date.now(), maximizedDoc, isMinimized);
+ }
+
+ }
+ })
+ }
+ onPointerDown = (e: React.PointerEvent): void => {
+ this._downX = e.clientX;
+ this._downY = e.clientY;
+ }
+ onClick = (e: React.MouseEvent): void => {
+ e.stopPropagation();
+ if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
+ Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
+ this.props.Document.GetTAsync(KeyStore.MaximizedDoc, Document).then(maxdoc => {
+ if (maxdoc instanceof Document) { // bcz: need a better way to associate behaviors with click events on widget-documents
+ this.props.addDocument && this.props.addDocument(maxdoc, false);
+ this.toggleIcon();
+ }
+ });
+ }
+ }
+
+ borderRounding = () => {
+ let br = this.props.Document.GetNumber(KeyStore.BorderRounding, 0);
+ return br >= 0 ? br :
+ this.props.Document.GetNumber(KeyStore.NativeWidth, 0) === 0 ?
+ Math.min(this.props.PanelWidth(), this.props.PanelHeight())
+ :
+ Math.min(this.props.Document.GetNumber(KeyStore.NativeWidth, 0), this.props.Document.GetNumber(KeyStore.NativeHeight, 0));
+ }
+
render() {
+ let maximizedDoc = this.props.Document.GetT(KeyStore.MaximizedDoc, Document);
let zoomFade = 1;
- //var zoom = doc.GetNumber(KeyStore.Zoom, 1);
- // let transform = this.getTransform().scale(this.contentScaling()).inverse();
- // var [sptX, sptY] = transform.transformPoint(0, 0);
- // let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight());
- // let w = bptX - sptX;
- // //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1;
- // let fadeUp = .75 * 1800;
- // let fadeDown = .075 * 1800;
- // zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1;
+ //var zoom = doc.GetNumber(KeyStore.ZoomBasis, 1);
+ let transform = this.getTransform().scale(this.contentScaling()).inverse();
+ var [sptX, sptY] = transform.transformPoint(0, 0);
+ let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight());
+ let w = bptX - sptX;
+ //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1;
+ const screenWidth = 1800;
+ let fadeUp = .75 * screenWidth;
+ let fadeDown = (maximizedDoc ? .0075 : .075) * screenWidth;
+ zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0.1, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1;
return (
- <div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
- opacity: zoomFade,
- transformOrigin: "left top",
- transform: this.transform,
- pointerEvents: (zoomFade < 0.09 ? "none" : "all"),
- width: this.width,
- height: this.height,
- position: "absolute",
- zIndex: this.zIndex,
- backgroundColor: "transparent"
- }} >
+ <div className="collectionFreeFormDocumentView-container" ref={this._mainCont}
+ onPointerDown={this.onPointerDown}
+ onClick={this.onClick}
+ style={{
+ opacity: zoomFade,
+ borderRadius: `${this.borderRounding()}px`,
+ transformOrigin: "left top",
+ transform: this.transform,
+ pointerEvents: (zoomFade < 0.09 ? "none" : "all"),
+ width: this.width,
+ height: this.height,
+ position: "absolute",
+ zIndex: this.zIndex,
+ backgroundColor: "transparent"
+ }} >
{this.docView}
</div>
);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 36850b734..bae14193e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -5,9 +5,7 @@ import { Field, FieldWaiting, Opt } from "../../../fields/Field";
import { Key } from "../../../fields/Key";
import { KeyStore } from "../../../fields/KeyStore";
import { ListField } from "../../../fields/ListField";
-import { NumberField } from "../../../fields/NumberField";
import { TemplateField } from "../../../fields/TemplateField";
-import { TextField } from "../../../fields/TextField";
import { ServerUtils } from "../../../server/ServerUtil";
import { emptyFunction, Utils } from "../../../Utils";
import { Documents } from "../../documents/Documents";
@@ -25,6 +23,9 @@ import { Template, Templates } from "./../Templates";
import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
import React = require("react");
+import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
+import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
+import { MarqueeView } from "../collections/collectionFreeForm/MarqueeView";
export interface DocumentViewProps {
ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
@@ -41,6 +42,7 @@ export interface DocumentViewProps {
selectOnLoad: boolean;
parentActive: () => boolean;
whenActiveChanged: (isActive: boolean) => void;
+ toggleMinimized: () => void;
}
export interface JsxArgs extends DocumentViewProps {
Keys: { [name: string]: Key };
@@ -84,7 +86,6 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
@observer
export class DocumentView extends React.Component<DocumentViewProps> {
- static _incompleteAnimations: Map<string, boolean> = new Map<string, boolean>();
private _downX: number = 0;
private _downY: number = 0;
@computed get base(): string { return this.props.Document.GetText(KeyStore.BaseLayout, "<p>Error loading base layout data</p>"); }
@@ -104,42 +105,16 @@ export class DocumentView extends React.Component<DocumentViewProps> {
set templates(templates: Array<Template>) { this.props.Document.SetData(KeyStore.Templates, templates, TemplateField); }
screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect();
- onPointerDown = (e: React.PointerEvent): void => {
- this._downX = e.clientX;
- this._downY = e.clientY;
- if (e.button === 2 && !this.isSelected()) {
- return;
- }
- if (e.shiftKey && e.buttons === 2) {
- if (this.props.isTopMost) {
- this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey);
- } else {
- CollectionDockingView.Instance.StartOtherDrag([this.props.Document], e);
- }
- e.stopPropagation();
- } else {
- let maxdoc = this.props.Document.GetT(KeyStore.MaximizedDoc, Document);
- if (this.active ||
- maxdoc instanceof Document // bcz: need a better way of allowing a document to handle pointer events when its not active (ie. be a top-level widget)
- ) {
- e.stopPropagation();
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
- }
- }
- }
-
+ @action
componentDidMount() {
if (this._mainCont.current) {
this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
handlers: { drop: this.drop.bind(this) }
});
}
- runInAction(() => DocumentManager.Instance.DocumentViews.push(this));
+ DocumentManager.Instance.DocumentViews.push(this);
}
-
+ @action
componentDidUpdate() {
if (this._dropDisposer) {
this._dropDisposer();
@@ -150,12 +125,16 @@ export class DocumentView extends React.Component<DocumentViewProps> {
});
}
}
-
+ @action
componentWillUnmount() {
if (this._dropDisposer) {
this._dropDisposer();
}
- runInAction(() => DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1));
+ DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1);
+ }
+
+ stopPropagation = (e: React.SyntheticEvent) => {
+ e.stopPropagation();
}
startDragging(x: number, y: number, dropAliasOfDraggedDoc: boolean) {
@@ -176,43 +155,56 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
}
- onPointerMove = (e: PointerEvent): void => {
- if (e.cancelBubble) {
+ onClick = (e: React.MouseEvent): void => {
+ if (CurrentUserUtils.MainDocId != this.props.Document.Id &&
+ (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
+ Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
+ SelectionManager.SelectDoc(this, e.ctrlKey);
+ }
+ }
+ onPointerDown = (e: React.PointerEvent): void => {
+ this._downX = e.clientX;
+ this._downY = e.clientY;
+ if (CollectionFreeFormView.RIGHT_BTN_DRAG && (e.button === 2 || (e.button === 0 && e.altKey)) && !this.isSelected()) {
return;
}
- if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
+ if (e.shiftKey && e.buttons === 1) {
+ if (this.props.isTopMost) {
+ this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey);
+ } else {
+ CollectionDockingView.Instance.StartOtherDrag([this.props.Document], e);
+ }
+ e.stopPropagation();
+ } else if (this.active) {
document.removeEventListener("pointermove", this.onPointerMove);
+ document.addEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
- if (!e.altKey && (!this.topMost || e.buttons === 2)) {
- this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey);
+ document.addEventListener("pointerup", this.onPointerUp);
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }
+ onPointerMove = (e: PointerEvent): void => {
+ if (!e.cancelBubble) {
+ if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ if (!e.altKey && !this.topMost && (!CollectionFreeFormView.RIGHT_BTN_DRAG && e.buttons === 1) || (CollectionFreeFormView.RIGHT_BTN_DRAG && e.buttons === 2)) {
+ this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey);
+ }
}
+ e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
+ e.preventDefault();
}
- e.stopPropagation();
- e.preventDefault();
}
onPointerUp = (e: PointerEvent): void => {
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
- e.stopPropagation();
- if (!SelectionManager.IsSelected(this) && e.button !== 2 &&
- Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) {
- this.props.Document.GetTAsync(KeyStore.MaximizedDoc, Document).then(maxdoc => {
- if (maxdoc instanceof Document) { // bcz: need a better way to associate behaviors with click events on widget-documents
- this.props.addDocument && this.props.addDocument(maxdoc, false);
- this.toggleIcon();
- } else
- SelectionManager.SelectDoc(this, e.ctrlKey);
- });
- }
- }
- stopPropagation = (e: React.SyntheticEvent) => {
- e.stopPropagation();
}
deleteClicked = (): void => {
this.props.removeDocument && this.props.removeDocument(this.props.Document);
}
-
fieldsClicked = (e: React.MouseEvent): void => {
let kvp = Documents.KVPDocument(this.props.Document, { width: 300, height: 300 });
CollectionDockingView.Instance.AddRightSplit(kvp);
@@ -223,7 +215,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked });
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
}
-
closeFullScreenClicked = (e: React.MouseEvent): void => {
CollectionDockingView.Instance.CloseFullScreen();
ContextMenu.Instance.clearItems();
@@ -231,136 +222,22 @@ export class DocumentView extends React.Component<DocumentViewProps> {
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
}
- @action createIcon = (layoutString: string): Document => {
- let iconDoc = Documents.IconDocument(layoutString);
- iconDoc.SetText(KeyStore.Title, "ICON" + this.props.Document.Title)
- iconDoc.SetBoolean(KeyStore.IsMinimized, false);
- iconDoc.SetNumber(KeyStore.NativeWidth, 0);
- iconDoc.SetNumber(KeyStore.NativeHeight, 0);
- iconDoc.SetNumber(KeyStore.X, this.props.Document.GetNumber(KeyStore.X, 0));
- iconDoc.SetNumber(KeyStore.Y, this.props.Document.GetNumber(KeyStore.Y, 0) - 24);
- iconDoc.Set(KeyStore.Prototype, this.props.Document);
- iconDoc.Set(KeyStore.MaximizedDoc, this.props.Document);
- this.props.Document.Set(KeyStore.MinimizedDoc, iconDoc);
- this.props.addDocument && this.props.addDocument(iconDoc, false);
- return iconDoc;
- }
-
- animateBetweenIcon(icon: number[], targ: number[], width: number, height: number, stime: number, target: Document, maximizing: boolean) {
- setTimeout(() => {
- let now = Date.now();
- let progress = Math.min(1, (now - stime) / 200);
- let pval = maximizing ?
- [icon[0] + (targ[0] - icon[0]) * progress, icon[1] + (targ[1] - icon[1]) * progress] :
- [targ[0] + (icon[0] - targ[0]) * progress, targ[1] + (icon[1] - targ[1]) * progress];
- target.SetNumber(KeyStore.Width, maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress);
- target.SetNumber(KeyStore.Height, maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress);
- target.SetNumber(KeyStore.X, pval[0]);
- target.SetNumber(KeyStore.Y, pval[1]);
- if (now < stime + 200) {
- this.animateBetweenIcon(icon, targ, width, height, stime, target, maximizing);
- }
- else {
- if (!maximizing) {
- target.SetBoolean(KeyStore.IsMinimized, true);
- target.SetNumber(KeyStore.X, targ[0]);
- target.SetNumber(KeyStore.Y, targ[1]);
- target.SetNumber(KeyStore.Width, width);
- target.SetNumber(KeyStore.Height, height);
- }
- DocumentView._incompleteAnimations.set(target.Id, false);
- }
- },
- 2);
- }
-
- @action
- public toggleIcon = async (): Promise<void> => {
- SelectionManager.DeselectAll();
- let isMinimized: boolean | undefined;
- let minDoc = await this.props.Document.GetTAsync(KeyStore.MinimizedDoc, Document);
- if (!minDoc) return;
- let minimizedDocSet = await minDoc.GetTAsync(KeyStore.LinkTags, ListField);
- if (!minimizedDocSet) return;
- minimizedDocSet.Data.map(async minimizedDoc => {
- if (minimizedDoc instanceof Document) {
- this.props.addDocument && this.props.addDocument(minimizedDoc, false);
- let maximizedDoc = await minimizedDoc.GetTAsync(KeyStore.MaximizedDoc, Document);
- if (maximizedDoc instanceof Document && !DocumentView._incompleteAnimations.get(maximizedDoc.Id)) {
- DocumentView._incompleteAnimations.set(maximizedDoc.Id, true);
- isMinimized = isMinimized === undefined ? maximizedDoc.GetBoolean(KeyStore.IsMinimized, false) : isMinimized;
- maximizedDoc.SetBoolean(KeyStore.IsMinimized, false);
- let minx = await minimizedDoc.GetTAsync(KeyStore.X, NumberField);
- let miny = await minimizedDoc.GetTAsync(KeyStore.Y, NumberField);
- let maxx = await maximizedDoc.GetTAsync(KeyStore.X, NumberField);
- let maxy = await maximizedDoc.GetTAsync(KeyStore.Y, NumberField);
- let maxw = await maximizedDoc.GetTAsync(KeyStore.Width, NumberField);
- let maxh = await maximizedDoc.GetTAsync(KeyStore.Height, NumberField);
- if (minx !== undefined && miny !== undefined && maxx !== undefined && maxy !== undefined &&
- maxw !== undefined && maxh !== undefined)
- this.animateBetweenIcon(
- [minx.Data, miny.Data], [maxx.Data, maxy.Data], maxw.Data, maxh.Data,
- Date.now(), maximizedDoc, isMinimized);
- }
-
- }
- })
- }
-
- @action
- public getIconDoc = async (): Promise<Document | undefined> => {
- return await this.props.Document.GetTAsync(KeyStore.MinimizedDoc, Document).then(async mindoc =>
- mindoc ? mindoc :
- await this.props.Document.GetTAsync(KeyStore.BackgroundLayout, TextField).then(async field =>
- (field instanceof TextField) ? this.createIcon(field.Data) :
- await this.props.Document.GetTAsync(KeyStore.Layout, TextField).then(field =>
- (field instanceof TextField) ? this.createIcon(field.Data) : undefined)));
- }
-
@undoBatch
@action
drop = (e: Event, de: DragManager.DropEvent) => {
if (de.data instanceof DragManager.LinkDragData) {
- let sourceDoc: Document = de.data.linkSourceDocument;
- let destDoc: Document = this.props.Document;
- let linkDoc: Document = new Document();
+ let sourceDoc = de.data.linkSourceDocument;
+ let destDoc = this.props.Document;
destDoc.GetTAsync(KeyStore.Prototype, Document).then(protoDest =>
sourceDoc.GetTAsync(KeyStore.Prototype, Document).then(protoSrc =>
- runInAction(() => {
- let batch = UndoManager.StartBatch("document view drop");
- linkDoc.SetText(KeyStore.Title, "New Link");
- linkDoc.SetText(KeyStore.LinkDescription, "");
- linkDoc.SetText(KeyStore.LinkTags, "Default");
-
- let dstTarg = protoDest ? protoDest : destDoc;
- let srcTarg = protoSrc ? protoSrc : sourceDoc;
- linkDoc.Set(KeyStore.LinkedToDocs, dstTarg);
- linkDoc.Set(KeyStore.LinkedFromDocs, srcTarg);
- const prom1 = new Promise(resolve => dstTarg.GetOrCreateAsync(
- KeyStore.LinkedFromDocs,
- ListField,
- field => {
- (field as ListField<Document>).Data.push(linkDoc);
- resolve();
- }
- ));
- const prom2 = new Promise(resolve => srcTarg.GetOrCreateAsync(
- KeyStore.LinkedToDocs,
- ListField,
- field => {
- (field as ListField<Document>).Data.push(linkDoc);
- resolve();
- }
- ));
- Promise.all([prom1, prom2]).finally(() => batch.end());
- })
- )
+ (protoSrc ? protoSrc : sourceDoc).CreateLink(protoDest ? protoDest : destDoc))
);
e.stopPropagation();
}
}
+ @action
onDrop = (e: React.DragEvent) => {
let text = e.dataTransfer.getData("text/plain");
if (!e.isDefaultPrevented() && text && text.startsWith("<div")) {
@@ -434,12 +311,10 @@ export class DocumentView extends React.Component<DocumentViewProps> {
isSelected = () => SelectionManager.IsSelected(this);
select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed);
-
@computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
@computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
@computed get contents() { return (<DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={KeyStore.Layout} />); }
-
render() {
var scaling = this.props.ContentScaling();
var nativeHeight = this.nativeHeight > 0 ? this.nativeHeight.toString() + "px" : "100%";
@@ -449,11 +324,12 @@ export class DocumentView extends React.Component<DocumentViewProps> {
<div className={`documentView-node${this.props.isTopMost ? "-topmost" : ""}`}
ref={this._mainCont}
style={{
+ borderRadius: "inherit",
background: this.props.Document.GetText(KeyStore.BackgroundColor, ""),
width: nativeWidth, height: nativeHeight,
transform: `scale(${scaling}, ${scaling})`
}}
- onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown}
+ onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
>
{this.contents}
</div>
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 93e385821..9e175b0d1 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -19,7 +19,7 @@ import { ListField } from "../../../fields/ListField";
import { DocumentContentsView } from "./DocumentContentsView";
import { Transform } from "../../util/Transform";
import { KeyStore } from "../../../fields/KeyStore";
-import { returnFalse, emptyDocFunction, emptyFunction, returnOne } from "../../../Utils";
+import { returnFalse, emptyDocFunction, emptyFunction, returnOne, returnZero } from "../../../Utils";
import { CollectionView } from "../collections/CollectionView";
import { CollectionPDFView } from "../collections/CollectionPDFView";
import { CollectionVideoView } from "../collections/CollectionVideoView";
@@ -47,6 +47,8 @@ export interface FieldViewProps {
active: () => boolean;
whenActiveChanged: (isActive: boolean) => void;
focus: (doc: Document) => void;
+ PanelWidth: () => number;
+ PanelHeight: () => number;
}
@observer
@@ -95,11 +97,12 @@ export class FieldView extends React.Component<FieldViewProps> {
isTopMost={true} //TODO Why is this top most?
selectOnLoad={false}
focus={emptyDocFunction}
- isSelected={returnFalse}
+ isSelected={this.props.isSelected}
select={returnFalse}
layoutKey={KeyStore.Layout}
ContainingCollectionView={this.props.ContainingCollectionView}
parentActive={this.props.active}
+ toggleMinimized={emptyFunction}
whenActiveChanged={this.props.whenActiveChanged} />
);
}
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 5eb2bf7ce..727d3c0b2 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -10,11 +10,11 @@
outline: none !important;
}
-.formattedTextBox-cont-scroll, .formattedTextBox-cont-hidden {
+.formattedTextBox-cont-scroll, .formattedTextBox-cont-hidden {
background: $light-color-secondary;
- padding: 0.9em;
+ padding: 0;
border-width: 0px;
- border-radius: $border-radius;
+ border-radius: inherit;
border-color: $intermediate-color;
box-sizing: border-box;
border-style: solid;
@@ -24,10 +24,19 @@
height: 100%;
pointer-events: all;
}
+
.formattedTextBox-cont-hidden {
overflow: hidden;
pointer-events: none;
}
+.formattedTextBox-inner-rounded {
+ height: calc(100% - 40px);
+ width: calc(100% - 40px);
+ position: absolute;
+ overflow: scroll;
+ top: 20;
+ left: 20;
+}
.menuicon {
display: inline-block;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 29ed2da13..fc8d757f6 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,4 +1,4 @@
-import { action, IReactionDisposer, reaction, trace, computed } from "mobx";
+import { action, IReactionDisposer, reaction, trace, computed, _allowStateChangesInsideComputed } from "mobx";
import { baseKeymap } from "prosemirror-commands";
import { history } from "prosemirror-history";
import { keymap } from "prosemirror-keymap";
@@ -21,8 +21,7 @@ import "./FormattedTextBox.scss";
import React = require("react");
import { SelectionManager } from "../../util/SelectionManager";
import { observer } from "mobx-react";
-const { buildMenuItems } = require("prosemirror-example-setup");
-const { menuBar } = require("prosemirror-menu");
+import { InkingControl } from "../InkingControl";
// FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document
//
@@ -66,9 +65,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
_applyingChange: boolean = false;
+ _lastState: any = undefined;
dispatchTransaction = (tx: Transaction) => {
if (this._editorView) {
- const state = this._editorView.state.apply(tx);
+ const state = this._lastState = this._editorView.state.apply(tx);
this._editorView.updateState(state);
this._applyingChange = true;
this.props.Document.SetDataOnPrototype(
@@ -87,10 +87,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
schema,
inpRules, //these currently don't do anything, but could eventually be helpful
plugins: this.props.isOverlay ? [
+ this.tooltipTextMenuPlugin(),
history(),
keymap(buildKeymap(schema)),
keymap(baseKeymap),
- this.tooltipTextMenuPlugin(),
// this.tooltipLinkingMenuPlugin(),
new Plugin({
props: {
@@ -166,19 +166,21 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
Document.SetOnPrototype(fieldKey, new RichTextField(e.target.value));
// doc.SetData(fieldKey, e.target.value, RichTextField);
}
+ @action
onPointerDown = (e: React.PointerEvent): void => {
- if (e.button === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
- console.log("first");
+ if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
e.stopPropagation();
+ if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip)
+ this._toolTipTextMenu.tooltip.style.opacity = "0";
}
- if (e.button === 2) {
+ if (e.button === 2 || (e.button === 0 && e.ctrlKey)) {
this._gotDown = true;
- console.log("second");
e.preventDefault();
}
}
onPointerUp = (e: React.PointerEvent): void => {
- console.log("pointer up");
+ if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip)
+ this._toolTipTextMenu.tooltip.style.opacity = "1";
if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
e.stopPropagation();
}
@@ -229,15 +231,21 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
}
}
+ onClick = (e: React.MouseEvent): void => {
+ this._ref.current!.focus();
+ }
+
tooltipTextMenuPlugin() {
let myprops = this.props;
+ let self = this;
return new Plugin({
view(_editorView) {
- return new TooltipTextMenu(_editorView, myprops);
+ return self._toolTipTextMenu = new TooltipTextMenu(_editorView, myprops);
}
});
}
+ _toolTipTextMenu: TooltipTextMenu | undefined = undefined;
tooltipLinkingMenuPlugin() {
let myprops = this.props;
return new Plugin({
@@ -247,29 +255,45 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
});
}
- onKeyPress(e: React.KeyboardEvent) {
+ @action
+ onKeyPress = (e: React.KeyboardEvent) => {
if (e.key == "Escape") {
SelectionManager.DeselectAll();
}
e.stopPropagation();
- if (e.keyCode === 9) e.preventDefault();
+ if (e.key === "Tab") e.preventDefault();
// stop propagation doesn't seem to stop propagation of native keyboard events.
// so we set a flag on the native event that marks that the event's been handled.
- // (e.nativeEvent as any).DASHFormattedTextBoxHandled = true;
+ (e.nativeEvent as any).DASHFormattedTextBoxHandled = true;
+ if (this.props.Document.Title.startsWith("-") && this._editorView) {
+ let str = this._editorView.state.doc.textContent;
+ let titlestr = str.substr(0, Math.min(40, str.length));
+ this.props.Document.SetText(KeyStore.Title, "-" + titlestr + (str.length > 40 ? "..." : ""));
+ };
}
render() {
- let style = this.props.isOverlay ? "scroll" : "hidden";
+ let style = this.props.isOverlay ? "-scroll" : "-hidden";
+ let rounded = this.props.Document.GetNumber(KeyStore.BorderRounding, 0) < 0 ? "-rounded" : "";
+ let color = this.props.Document.GetText(KeyStore.BackgroundColor, "");
+ let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive";
return (
- <div className={`formattedTextBox-cont-${style}`}
+ <div className={`formattedTextBox-cont${style}`}
+ style={{
+ pointerEvents: interactive ? "all" : "none",
+ background: color,
+ }}
onKeyDown={this.onKeyPress}
onKeyPress={this.onKeyPress}
onFocus={this.onFocused}
+ onClick={this.onClick}
onPointerUp={this.onPointerUp}
onPointerDown={this.onPointerDown}
onContextMenu={this.specificContextMenu}
// tfs: do we need this event handler
onWheel={this.onPointerWheel}
- ref={this._ref} />
+ >
+ <div className={`formattedTextBox-inner${rounded}`} ref={this._ref} />
+ </div>
);
}
}
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index f4b3837ff..9fe211df0 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -6,6 +6,10 @@
height: auto;
max-width: 100%;
max-height: 100%;
+ pointer-events: none;
+}
+.imageBox-cont-interactive {
+ pointer-events: all;
}
.imageBox-dot {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index ce855384c..2cbb0fa90 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -15,6 +15,8 @@ import { ContextMenu } from "../../views/ContextMenu";
import { FieldView, FieldViewProps } from './FieldView';
import "./ImageBox.scss";
import React = require("react");
+import { InkingControl } from '../InkingControl';
+import { NumberField } from '../../../fields/NumberField';
@observer
export class ImageBox extends React.Component<FieldViewProps> {
@@ -40,7 +42,8 @@ export class ImageBox extends React.Component<FieldViewProps> {
var w = this._imgRef.current!.naturalWidth;
if (this._photoIndex === 0) {
this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w);
- this.props.Document.SetNumber(KeyStore.Height, this.props.Document.Width() * h / w);
+ this.props.Document.GetTAsync(KeyStore.Width, NumberField, field =>
+ field && this.props.Document.SetNumber(KeyStore.Height, field.Data * h / w));
}
}
@@ -87,7 +90,6 @@ export class ImageBox extends React.Component<FieldViewProps> {
onPointerDown = (e: React.PointerEvent): void => {
if (Date.now() - this._lastTap < 300) {
if (e.buttons === 1) {
- e.stopPropagation();
this._downX = e.clientX;
this._downY = e.clientY;
document.removeEventListener("pointerup", this.onPointerUp);
@@ -161,8 +163,9 @@ export class ImageBox extends React.Component<FieldViewProps> {
else if (field instanceof ImageField) paths = [field.Data.href];
else if (field instanceof ListField) paths = field.Data.filter(val => val as ImageField).map(p => (p as ImageField).Data.href);
let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1);
+ let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive";
return (
- <div className="imageBox-cont" onPointerDown={this.onPointerDown} onDrop={this.onDrop} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
+ <div className={`imageBox-cont${interactive}`} onPointerDown={this.onPointerDown} onDrop={this.onDrop} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
<img src={paths[Math.min(paths.length, this._photoIndex)]} style={{ objectFit: (this._photoIndex === 0 ? undefined : "contain") }} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} />
{paths.length > 1 ? this.dots(paths) : (null)}
{this.lightbox(paths)}
diff --git a/src/client/views/nodes/KeyValueBox.scss b/src/client/views/nodes/KeyValueBox.scss
index 6ebd73f2c..20cae03d4 100644
--- a/src/client/views/nodes/KeyValueBox.scss
+++ b/src/client/views/nodes/KeyValueBox.scss
@@ -8,6 +8,7 @@
border-radius: $border-radius;
box-sizing: border-box;
display: inline-block;
+ pointer-events: all;
.imageBox-cont img {
width: auto;
}
diff --git a/src/client/views/nodes/KeyValuePair.scss b/src/client/views/nodes/KeyValuePair.scss
index 01701e02c..ff6885965 100644
--- a/src/client/views/nodes/KeyValuePair.scss
+++ b/src/client/views/nodes/KeyValuePair.scss
@@ -25,4 +25,5 @@
}
.keyValuePair-td-value {
display:inline-block;
+ overflow: scroll;
} \ No newline at end of file
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 830dfe6c6..3760e378a 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -4,6 +4,9 @@
top: 0;
left:0;
}
+.react-pdf__Page__textContent span {
+ user-select: text;
+}
.react-pdf__Document {
position: absolute;
}
@@ -12,6 +15,21 @@
top: 0;
left:0;
z-index: 25;
+ pointer-events: all;
+}
+.pdfButton {
+ pointer-events: all;
+ width: 100px;
+ height:100px;
+}
+.pdfBox-cont {
+ pointer-events: none ;
+ span {
+ pointer-events: none !important;
+ }
+}
+.pdfBox-cont-interactive {
+ pointer-events: all;
}
.pdfBox-contentContainer {
position: absolute;
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 81ceb37f6..226dfba11 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -1,5 +1,5 @@
import * as htmlToImage from "html-to-image";
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, reaction, Reaction, trace } from 'mobx';
import { observer } from "mobx-react";
import 'react-image-lightbox/style.css';
import Measure from "react-measure";
@@ -14,11 +14,10 @@ import { RouteStore } from "../../../server/RouteStore";
import { Utils } from '../../../Utils';
import { Annotation } from './Annotation';
import { FieldView, FieldViewProps } from './FieldView';
-import "./ImageBox.scss";
import "./PDFBox.scss";
-import { Sticky } from './Sticky'; //you should look at sticky and annotation, because they are used here
import React = require("react");
import { SelectionManager } from "../../util/SelectionManager";
+import { InkingControl } from "../InkingControl";
/** ALSO LOOK AT: Annotation.tsx, Sticky.tsx
* This method renders PDF and puts all kinds of functionalities such as annotation, highlighting,
@@ -40,15 +39,6 @@ import { SelectionManager } from "../../util/SelectionManager";
* 4) another method: click on highlight first and then drag on your desired text
* 5) To make another highlight, you need to reclick on the button
*
- * Draw:
- * 1) click draw and select color. then just draw like there's no tomorrow.
- * 2) once you finish drawing your masterpiece, just reclick on the draw button to end your drawing session.
- *
- * Pagination:
- * 1) click on arrows. You'll notice that stickies will stay in those page. But... highlights won't.
- * 2) to test this out, make few area/stickies and then click on next page then come back. You'll see that they are all saved.
- *
- *
* written by: Andrew Kim
*/
@observer
@@ -56,30 +46,9 @@ export class PDFBox extends React.Component<FieldViewProps> {
public static LayoutString() { return FieldView.LayoutString(PDFBox); }
private _mainDiv = React.createRef<HTMLDivElement>();
- private _pdf = React.createRef<HTMLCanvasElement>();
@observable private _renderAsSvg = true;
- //very useful for keeping track of X and y position throughout the PDF Canvas
- private initX: number = 0;
- private initY: number = 0;
-
- //checks if tool is on
- private _toolOn: boolean = false; //checks if tool is on
- private _pdfContext: any = null; //gets pdf context
- private bool: Boolean = false; //general boolean debounce
- private currSpan: any;//keeps track of current span (for highlighting)
-
- private _currTool: any; //keeps track of current tool button reference
- private _drawToolOn: boolean = false; //boolean that keeps track of the drawing tool
- private _drawTool = React.createRef<HTMLButtonElement>();//drawing tool button reference
-
- private _colorTool = React.createRef<HTMLButtonElement>(); //color button reference
- private _currColor: string = "black"; //current color that user selected (for ink/pen)
-
- private _highlightTool = React.createRef<HTMLButtonElement>(); //highlighter button reference
- private _highlightToolOn: boolean = false;
- private _pdfCanvas: any;
private _reactionDisposer: Opt<IReactionDisposer>;
@observable private _perPageInfo: Object[] = []; //stores pageInfo
@@ -112,43 +81,6 @@ export class PDFBox extends React.Component<FieldViewProps> {
}
/**
- * selection tool used for area highlighting (stickies). Kinda temporary
- */
- selectionTool = () => {
- this._toolOn = true;
- }
- /**
- * when user draws on the canvas. When mouse pointer is down
- */
- drawDown = (e: PointerEvent) => {
- this.initX = e.offsetX;
- this.initY = e.offsetY;
- this._pdfContext.beginPath();
- this._pdfContext.lineTo(this.initX, this.initY);
- this._pdfContext.strokeStyle = this._currColor;
- this._pdfCanvas.addEventListener("pointermove", this.drawMove);
- this._pdfCanvas.addEventListener("pointerup", this.drawUp);
-
- }
- //when user drags
- drawMove = (e: PointerEvent): void => {
- //x and y mouse movement
- let x = this.initX += e.movementX,
- y = this.initY += e.movementY;
- //connects the point
- this._pdfContext.lineTo(x, y);
- this._pdfContext.stroke();
- }
-
- drawUp = (e: PointerEvent) => {
- this._pdfContext.closePath();
- this._pdfCanvas.removeEventListener("pointermove", this.drawMove);
- this._pdfCanvas.removeEventListener("pointerdown", this.drawDown);
- this._pdfCanvas.addEventListener("pointerdown", this.drawDown);
- }
-
-
- /**
* highlighting helper function
*/
makeEditableAndHighlight = (colour: string) => {
@@ -183,7 +115,7 @@ export class PDFBox extends React.Component<FieldViewProps> {
child.id = "highlighted";
//@ts-ignore
obj.spans.push(child);
- child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler
+ // child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler
}
});
}
@@ -206,7 +138,7 @@ export class PDFBox extends React.Component<FieldViewProps> {
child.id = "highlighted";
//@ts-ignore
temp.spans.push(child);
- child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler
+ // child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler
}
});
@@ -272,11 +204,20 @@ export class PDFBox extends React.Component<FieldViewProps> {
* controls the area highlighting (stickies) Kinda temporary
*/
onPointerDown = (e: React.PointerEvent) => {
- if (this._toolOn) {
- let mouse = e.nativeEvent;
- this.initX = mouse.offsetX;
- this.initY = mouse.offsetY;
-
+ if (this.props.isSelected() && !InkingControl.Instance.selectedTool && e.buttons === 1) {
+ if (e.altKey) {
+ this._alt = true;
+ } else {
+ if (e.metaKey)
+ e.stopPropagation();
+ }
+ document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointerup", this.onPointerUp);
+ }
+ if (this.props.isSelected() && e.buttons === 2) {
+ this._alt = true;
+ document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointerup", this.onPointerUp);
}
}
@@ -284,96 +225,15 @@ export class PDFBox extends React.Component<FieldViewProps> {
* controls area highlighting and partially highlighting. Kinda temporary
*/
@action
- onPointerUp = (e: React.PointerEvent) => {
- if (this._highlightToolOn) {
+ onPointerUp = (e: PointerEvent) => {
+ this._alt = false;
+ document.removeEventListener("pointerup", this.onPointerUp);
+ if (this.props.isSelected()) {
this.highlight("rgba(76, 175, 80, 0.3)"); //highlights to this default color.
- this._highlightToolOn = false;
- }
- if (this._toolOn) {
- let mouse = e.nativeEvent;
- let finalX = mouse.offsetX;
- let finalY = mouse.offsetY;
- let width = Math.abs(finalX - this.initX); //width
- let height = Math.abs(finalY - this.initY); //height
-
- //these two if statements are bidirectional dragging. You can drag from any point to another point and generate sticky
- if (finalX < this.initX) {
- this.initX = finalX;
- }
- if (finalY < this.initY) {
- this.initY = finalY;
- }
-
- if (this._mainDiv.current) {
- let sticky = <Sticky key={Utils.GenerateGuid()} Height={height} Width={width} X={this.initX} Y={this.initY} />;
- this._pageInfo.area.push(sticky);
- }
- this._toolOn = false;
}
this._interactive = true;
}
- /**
- * starts drawing the line when user presses down.
- */
- onDraw = () => {
- if (this._currTool !== null) {
- this._currTool.style.backgroundColor = "grey";
- }
-
- if (this._drawTool.current) {
- this._currTool = this._drawTool.current;
- if (this._drawToolOn) {
- this._drawToolOn = false;
- this._pdfCanvas.removeEventListener("pointerdown", this.drawDown);
- this._pdfCanvas.removeEventListener("pointerup", this.drawUp);
- this._pdfCanvas.removeEventListener("pointermove", this.drawMove);
- this._drawTool.current.style.backgroundColor = "grey";
- } else {
- this._drawToolOn = true;
- this._pdfCanvas.addEventListener("pointerdown", this.drawDown);
- this._drawTool.current.style.backgroundColor = "cyan";
- }
- }
- }
-
-
- /**
- * for changing color (for ink/pen)
- */
- onColorChange = (e: React.PointerEvent) => {
- if (e.currentTarget.innerHTML === "Red") {
- this._currColor = "red";
- } else if (e.currentTarget.innerHTML === "Blue") {
- this._currColor = "blue";
- } else if (e.currentTarget.innerHTML === "Green") {
- this._currColor = "green";
- } else if (e.currentTarget.innerHTML === "Black") {
- this._currColor = "black";
- }
-
- }
-
-
- /**
- * For highlighting (text drag highlighting)
- */
- onHighlight = () => {
- this._drawToolOn = false;
- if (this._currTool !== null) {
- this._currTool.style.backgroundColor = "grey";
- }
- if (this._highlightTool.current) {
- this._currTool = this._drawTool.current;
- if (this._highlightToolOn) {
- this._highlightToolOn = false;
- this._highlightTool.current.style.backgroundColor = "grey";
- } else {
- this._highlightToolOn = true;
- this._highlightTool.current.style.backgroundColor = "orange";
- }
- }
- }
@action
@@ -397,22 +257,6 @@ export class PDFBox extends React.Component<FieldViewProps> {
@action
onLoaded = (page: any) => {
- if (this._mainDiv.current) {
- this._mainDiv.current.childNodes.forEach((element) => {
- if (element.nodeName === "DIV") {
- element.childNodes[0].childNodes.forEach((e) => {
-
- if (e instanceof HTMLCanvasElement) {
- this._pdfCanvas = e;
- this._pdfContext = e.getContext("2d");
-
- }
-
- });
- }
- });
- }
-
// bcz: the number of pages should really be set when the document is imported.
this.props.Document.SetNumber(KeyStore.NumPages, page._transport.numPages);
if (this._perPageInfo.length === 0) { //Makes sure it only runs once
@@ -424,7 +268,7 @@ export class PDFBox extends React.Component<FieldViewProps> {
@action
setScaling = (r: any) => {
// bcz: the nativeHeight should really be set when the document is imported.
- // also, the native dimensions could be different for different pages of the PDF
+ // also, the native dimensions could be different for different pages of the canvas
// so this design is flawed.
var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0);
if (!this.props.Document.GetNumber(KeyStore.NativeHeight, 0)) {
@@ -433,22 +277,27 @@ export class PDFBox extends React.Component<FieldViewProps> {
this.props.Document.SetNumber(KeyStore.NativeHeight, nativeHeight);
}
}
-
+ renderHeight = 2400;
+ @computed
+ get pdfPage() {
+ return <Page height={this.renderHeight} pageNumber={this.curPage} onLoadSuccess={this.onLoaded} />
+ }
@computed
get pdfContent() {
- let page = this.curPage;
- const renderHeight = 2400;
let pdfUrl = this.props.Document.GetT(this.props.fieldKey, PDFField);
- let xf = this.props.Document.GetNumber(KeyStore.NativeHeight, 0) / renderHeight;
+ let xf = this.props.Document.GetNumber(KeyStore.NativeHeight, 0) / this.renderHeight;
+ let body = (this.props.Document.GetNumber(KeyStore.NativeHeight, 0)) ?
+ this.pdfPage :
+ <Measure onResize={this.setScaling}>
+ {({ measureRef }) =>
+ <div className="pdfBox-page" ref={measureRef}>
+ {this.pdfPage}
+ </div>
+ }
+ </Measure>;
return <div className="pdfBox-contentContainer" key="container" style={{ transform: `scale(${xf}, ${xf})` }}>
- <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl}`} renderMode={this._renderAsSvg ? "svg" : ""}>
- <Measure onResize={this.setScaling}>
- {({ measureRef }) =>
- <div className="pdfBox-page" ref={measureRef}>
- <Page height={renderHeight} pageNumber={page} onLoadSuccess={this.onLoaded} />
- </div>
- }
- </Measure>
+ <Document file={window.origin + RouteStore.corsProxy + `/${pdfUrl}`} renderMode={this._renderAsSvg ? "svg" : "canvas"}>
+ {body}
</Document>
</div >;
}
@@ -478,10 +327,24 @@ export class PDFBox extends React.Component<FieldViewProps> {
}
return (null);
}
-
+ @observable _alt = false;
+ @action
+ onKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === "Alt") {
+ this._alt = true;
+ }
+ }
+ @action
+ onKeyUp = (e: React.KeyboardEvent) => {
+ if (e.key === "Alt") {
+ this._alt = false;
+ }
+ }
render() {
+ trace();
+ let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
return (
- <div className="pdfBox-cont" ref={this._mainDiv} onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp} >
+ <div className={classname} tabIndex={0} ref={this._mainDiv} onPointerDown={this.onPointerDown} onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} >
{this.pdfRenderer}
</div >
);
diff --git a/src/client/views/nodes/Sticky.tsx b/src/client/views/nodes/Sticky.tsx
deleted file mode 100644
index 11719831b..000000000
--- a/src/client/views/nodes/Sticky.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import "react-image-lightbox/style.css"; // This only needs to be imported once in your app
-import React = require("react");
-import { observer } from "mobx-react";
-import "react-pdf/dist/Page/AnnotationLayer.css";
-
-interface IProps {
- Height: number;
- Width: number;
- X: number;
- Y: number;
-}
-
-/**
- * Sticky, also known as area highlighting, is used to highlight large selection of the PDF file.
- * Improvements that could be made: maybe store line array and store that somewhere for future rerendering.
- *
- * Written By: Andrew Kim
- */
-@observer
-export class Sticky extends React.Component<IProps> {
- private initX: number = 0;
- private initY: number = 0;
-
- private _ref = React.createRef<HTMLCanvasElement>();
- private ctx: any; //context that keeps track of sticky canvas
-
- /**
- * drawing. Registers the first point that user clicks when mouse button is pressed down on canvas
- */
- drawDown = (e: React.PointerEvent) => {
- if (this._ref.current) {
- this.ctx = this._ref.current.getContext("2d");
- let mouse = e.nativeEvent;
- this.initX = mouse.offsetX;
- this.initY = mouse.offsetY;
- this.ctx.beginPath();
- this.ctx.lineTo(this.initX, this.initY);
- this.ctx.strokeStyle = "black";
- document.addEventListener("pointermove", this.drawMove);
- document.addEventListener("pointerup", this.drawUp);
- }
- }
-
- //when user drags
- drawMove = (e: PointerEvent): void => {
- //x and y mouse movement
- let x = (this.initX += e.movementX),
- y = (this.initY += e.movementY);
- //connects the point
- this.ctx.lineTo(x, y);
- this.ctx.stroke();
- }
-
- /**
- * when user lifts the mouse, the drawing ends
- */
- drawUp = (e: PointerEvent) => {
- this.ctx.closePath();
- console.log(this.ctx);
- document.removeEventListener("pointermove", this.drawMove);
- }
-
- render() {
- return (
- <div onPointerDown={this.drawDown}>
- <canvas
- ref={this._ref}
- height={this.props.Height}
- width={this.props.Width}
- style={{
- position: "absolute",
- top: "20px",
- left: "0px",
- zIndex: 1,
- background: "yellow",
- transform: `translate(${this.props.X}px, ${this.props.Y}px)`,
- opacity: 0.4
- }}
- />
- </div>
- );
- }
-}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 1e6bc58c9..b34f1dc08 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -11,7 +11,6 @@ import "./VideoBox.scss";
@observer
export class VideoBox extends React.Component<FieldViewProps> {
- private _reactionDisposer: Opt<IReactionDisposer>;
private _videoRef = React.createRef<HTMLVideoElement>();
public static LayoutString() { return FieldView.LayoutString(VideoBox); }
@@ -53,25 +52,26 @@ export class VideoBox extends React.Component<FieldViewProps> {
(vref as any).AHackBecauseSomethingResetsTheVideoToZero = this.curPage;
}
}
+ videoContent(path: string) {
+ return <video className="videobox-cont" ref={this.setVideoRef}>
+ <source src={path} type="video/mp4" />
+ Not supported.
+ </video>;
+ }
render() {
let field = this.props.Document.GetT(this.props.fieldKey, VideoField);
if (!field || field === FieldWaiting) {
return <div>Loading</div>;
}
- let path = field.Data.href;
- trace();
- return (
+ return (this.props.Document.GetNumber(KeyStore.NativeHeight, 0)) ?
+ this.videoContent(field.data.href) :
<Measure onResize={this.setScaling}>
{({ measureRef }) =>
<div style={{ width: "100%", height: "auto" }} ref={measureRef}>
- <video className="videobox-cont" ref={this.setVideoRef}>
- <source src={path} type="video/mp4" />
- Not supported.
- </video>
+ {this.videoContent(field.data.href)}
</div>
}
- </Measure>
- );
+ </Measure>;
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index 2ad1129a4..eb09b0693 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -1,12 +1,19 @@
-.webBox-cont {
+.webBox-cont, .webBox-cont-interactive{
padding: 0vw;
position: absolute;
top: 0;
left:0;
width: 100%;
height: 100%;
- overflow: scroll;
+ overflow: auto;
+ pointer-events: none ;
+}
+.webBox-cont-interactive {
+ pointer-events: all;
+ span {
+ user-select: text !important;
+ }
}
#webBox-htmlSpan {
@@ -15,6 +22,12 @@
left:0;
}
+.webBox-overlay {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+}
+
.webBox-button {
padding : 0vw;
border: none;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index f7f5e31e6..a7c6fda8b 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -7,6 +7,7 @@ import { observer } from "mobx-react";
import { computed, reaction, IReactionDisposer } from 'mobx';
import { KeyStore } from '../../../fields/KeyStore';
import { DocumentDecorations } from "../DocumentDecorations";
+import { InkingControl } from "../InkingControl";
@observer
export class WebBox extends React.Component<FieldViewProps> {
@@ -45,12 +46,13 @@ export class WebBox extends React.Component<FieldViewProps> {
let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
+ let classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
return (
<>
- <div className="webBox-cont" >
+ <div className={classname} >
{content}
</div>
- {!frozen ? (null) : <div onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer} style={{ width: "100%", height: "100%", position: "absolute" }} />}
+ {!frozen ? (null) : <div className="webBox-overlay" onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer} />}
</>);
}
} \ No newline at end of file