aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/DocumentDecorations.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/DocumentDecorations.tsx')
-rw-r--r--src/client/views/DocumentDecorations.tsx496
1 files changed, 244 insertions, 252 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index c5034b901..79600b7c1 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,15 +1,14 @@
import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
+import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTextHeight, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, reaction } from "mobx";
+import { action, computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc } from "../../new_fields/Doc";
+import { Doc, DataSym } from "../../new_fields/Doc";
import { PositionDocument } from '../../new_fields/documentSchemas';
-import { ObjectField } from '../../new_fields/ObjectField';
import { ScriptField } from '../../new_fields/ScriptField';
-import { Cast, StrCast } from "../../new_fields/Types";
+import { Cast, StrCast, NumCast } from "../../new_fields/Types";
import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
-import { Utils } from "../../Utils";
+import { Utils, setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils";
import { DocUtils } from "../documents/Documents";
import { DocumentType } from '../documents/DocumentTypes';
import { DragManager } from "../util/DragManager";
@@ -18,12 +17,15 @@ import { undoBatch, UndoManager } from "../util/UndoManager";
import { DocumentButtonBar } from './DocumentButtonBar';
import './DocumentDecorations.scss';
import { DocumentView } from "./nodes/DocumentView";
-import { IconBox } from "./nodes/IconBox";
import React = require("react");
-const higflyout = require("@hig/flyout");
-export const { anchorPoints } = higflyout;
-export const Flyout = higflyout.default;
+import { Id } from '../../new_fields/FieldSymbols';
+import e = require('express');
+library.add(faCaretUp);
+library.add(faObjectGroup);
+library.add(faStickyNote);
+library.add(faFilePdf);
+library.add(faFilm, faTextHeight);
library.add(faLink);
library.add(faTag);
library.add(faTimes);
@@ -35,41 +37,71 @@ library.add(faCloudUploadAlt);
library.add(faSyncAlt);
library.add(faShare);
+export type CloseCall = (toBeDeleted: DocumentView[]) => void;
+
@observer
export class DocumentDecorations extends React.Component<{}, { value: string }> {
static Instance: DocumentDecorations;
- private _isPointerDown = false;
- private _resizing = "";
- private _keyinput: React.RefObject<HTMLInputElement>;
+ private _resizeHdlId = "";
+ private _keyinput = React.createRef<HTMLInputElement>();
private _resizeBorderWidth = 16;
private _linkBoxHeight = 20 + 3; // link button height + margin
private _titleHeight = 20;
- private _downX = 0;
- private _downY = 0;
private _resizeUndo?: UndoManager.Batch;
- private _radiusDown = [0, 0];
@observable private _accumulatedTitle = "";
@observable private _titleControlString: string = "#title";
@observable private _edtingTitle = false;
@observable private _hidden = false;
- @observable private _opacity = 1;
- @observable public Interacting = false;
+ @observable private _addedCloseCalls: CloseCall[] = [];
+ @observable public Interacting = false;
@observable public pushIcon: IconProp = "arrow-alt-circle-up";
@observable public pullIcon: IconProp = "arrow-alt-circle-down";
@observable public pullColor: string = "white";
- @observable public openHover = false;
constructor(props: Readonly<{}>) {
super(props);
DocumentDecorations.Instance = this;
- this._keyinput = React.createRef();
reaction(() => SelectionManager.SelectedDocuments().slice(), docs => this.titleBlur(false));
}
- @action titleChanged = (event: any) => this._accumulatedTitle = event.target.value;
+ @computed
+ get Bounds(): { x: number, y: number, b: number, r: number } {
+ return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
+ if (documentView.props.renderDepth === 0 ||
+ //documentView.props.Document.dontSelect ||
+ Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) {
+ return bounds;
+ }
+ const transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
+ var [sptX, sptY] = transform.transformPoint(0, 0);
+ let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
+ if (documentView.props.Document.type === DocumentType.LINK) {
+ const docuBox = documentView.ContentDiv!.getElementsByClassName("docuLinkBox-cont");
+ if (docuBox.length) {
+ const rect = docuBox[0].getBoundingClientRect();
+ sptX = rect.left;
+ sptY = rect.top;
+ bptX = rect.right;
+ bptY = rect.bottom;
+ }
+ }
+ return {
+ x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y),
+ r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b)
+ };
+ }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE });
+ }
- titleBlur = undoBatch(action((commit: boolean) => {
+ addCloseCall = (handler: CloseCall) => {
+ const currentOffset = this._addedCloseCalls.length - 1;
+ this._addedCloseCalls.push((toBeDeleted: DocumentView[]) => {
+ this._addedCloseCalls.splice(currentOffset, 1);
+ handler(toBeDeleted);
+ });
+ }
+
+ titleBlur = action((commit: boolean) => {
this._edtingTitle = false;
if (commit) {
if (this._accumulatedTitle.startsWith("#") || this._accumulatedTitle.startsWith("=")) {
@@ -77,12 +109,13 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
} else if (this._titleControlString.startsWith("#")) {
const selectionTitleFieldKey = this._titleControlString.substring(1);
selectionTitleFieldKey === "title" && (SelectionManager.SelectedDocuments()[0].props.Document.customTitle = !this._accumulatedTitle.startsWith("-"));
- selectionTitleFieldKey && SelectionManager.SelectedDocuments().forEach(d =>
- Doc.SetInPlace(d.props.Document, selectionTitleFieldKey, typeof d.props.Document[selectionTitleFieldKey] === "number" ? +this._accumulatedTitle : this._accumulatedTitle, true)
- );
+ UndoManager.RunInBatch(() => selectionTitleFieldKey && SelectionManager.SelectedDocuments().forEach(d => {
+ const value = typeof d.props.Document[selectionTitleFieldKey] === "number" ? +this._accumulatedTitle : this._accumulatedTitle;
+ Doc.SetInPlace(d.props.Document, selectionTitleFieldKey, value, true);
+ }), "title blur");
}
}
- }));
+ });
@action titleEntered = (e: any) => {
const key = e.keyCode || e.which;
@@ -90,92 +123,69 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (key === 13) {
const text = e.target.value;
if (text.startsWith("::")) {
- const targetID = text.slice(2, text.length);
+ this._accumulatedTitle = text.slice(2, text.length);
const promoteDoc = SelectionManager.SelectedDocuments()[0];
- DocUtils.Publish(promoteDoc.props.Document, targetID, promoteDoc.props.addDocument, promoteDoc.props.removeDocument);
- } else if (text.startsWith(">")) {
- const fieldTemplateView = SelectionManager.SelectedDocuments()[0];
- SelectionManager.DeselectAll();
- const fieldTemplate = fieldTemplateView.props.Document;
- const containerView = fieldTemplateView.props.ContainingCollectionView;
- const docTemplate = fieldTemplateView.props.ContainingCollectionDoc;
- if (containerView && docTemplate) {
- const metaKey = text.startsWith(">>") ? text.slice(2, text.length) : text.slice(1, text.length);
- if (metaKey !== containerView.props.fieldKey && containerView.props.DataDoc) {
- const fd = fieldTemplate.data;
- fd instanceof ObjectField && (Doc.GetProto(containerView.props.DataDoc)[metaKey] = ObjectField.MakeCopy(fd));
- }
- fieldTemplate.title = metaKey;
- Doc.MakeMetadataFieldTemplate(fieldTemplate, Doc.GetProto(docTemplate));
- if (text.startsWith(">>")) {
- Doc.GetProto(docTemplate).layout = StrCast(fieldTemplateView.props.Document.layout).replace(/fieldKey={'[^']*'}/, `fieldKey={"${metaKey}"}`);
- }
- }
+ Doc.SetInPlace(promoteDoc.props.Document, "title", this._accumulatedTitle, true);
+ DocUtils.Publish(promoteDoc.props.Document, this._accumulatedTitle, promoteDoc.props.addDocument, promoteDoc.props.removeDocument);
}
e.target.blur();
}
}
@action onTitleDown = (e: React.PointerEvent): void => {
- this._downX = e.clientX;
- this._downY = e.clientY;
- e.stopPropagation();
- document.removeEventListener("pointermove", this.onTitleMove);
- document.removeEventListener("pointerup", this.onTitleUp);
- document.addEventListener("pointermove", this.onTitleMove);
- document.addEventListener("pointerup", this.onTitleUp);
+ setupMoveUpEvents(this, e, this.onBackgroundMove, (e) => { }, this.onTitleClick);
}
- @action onTitleMove = (e: PointerEvent): void => {
- if (Math.abs(e.clientX - this._downX) > 4 || Math.abs(e.clientY - this._downY) > 4) {
- this.Interacting = true;
- }
- if (this.Interacting) this.onBackgroundMove(e);
- e.stopPropagation();
+ @action onTitleClick = (e: PointerEvent): void => {
+ !this._edtingTitle && (this._accumulatedTitle = this._titleControlString.startsWith("#") ? this.selectionTitle : this._titleControlString);
+ this._edtingTitle = true;
+ setTimeout(() => this._keyinput.current!.focus(), 0);
}
- @action onTitleUp = (e: PointerEvent): void => {
- if (Math.abs(e.clientX - this._downX) < 4 || Math.abs(e.clientY - this._downY) < 4) {
- !this._edtingTitle && (this._accumulatedTitle = this._titleControlString.startsWith("#") ? this.selectionTitle : this._titleControlString);
- this._edtingTitle = true;
- setTimeout(() => this._keyinput.current!.focus(), 0);
- }
- document.removeEventListener("pointermove", this.onTitleMove);
- document.removeEventListener("pointerup", this.onTitleUp);
- this.onBackgroundUp(e);
+
+ @action onSettingsDown = (e: React.PointerEvent): void => {
+ setupMoveUpEvents(this, e, () => false, (e) => { }, this.onSettingsClick);
}
- @computed
- get Bounds(): { x: number, y: number, b: number, r: number } {
- return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
- if (documentView.props.renderDepth === 0 ||
- Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) {
- return bounds;
- }
- const transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
- var [sptX, sptY] = transform.transformPoint(0, 0);
- let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
- if (documentView.props.Document.type === DocumentType.LINK) {
- const rect = documentView.ContentDiv!.getElementsByClassName("docuLinkBox-cont")[0].getBoundingClientRect();
- sptX = rect.left;
- sptY = rect.top;
- bptX = rect.right;
- bptY = rect.bottom;
- }
- return {
- x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y),
- r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b)
- };
- }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE });
+ simulateMouseClick(element: Element, x: number, y: number, sx: number, sy: number) {
+ ["pointerdown", "pointerup"].map(event => element.dispatchEvent(
+ new PointerEvent(event, {
+ view: window,
+ bubbles: true,
+ cancelable: true,
+ button: 2,
+ pointerType: "mouse",
+ clientX: x,
+ clientY: y,
+ screenX: sx,
+ screenY: sy,
+ })));
+
+ element.dispatchEvent(
+ new MouseEvent("contextmenu", {
+ view: window,
+ bubbles: true,
+ cancelable: true,
+ button: 2,
+ clientX: x,
+ clientY: y,
+ movementX: 0,
+ movementY: 0,
+ screenX: sx,
+ screenY: sy,
+ }));
+ }
+ @action onSettingsClick = (e: PointerEvent): void => {
+ if (e.button === 0 && !e.altKey && !e.ctrlKey) {
+ let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0];
+ while (child.children.length && child.className !== "jsx-parser") child = child.children[0];
+ this.simulateMouseClick(child.children[0], e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
+ }
}
onBackgroundDown = (e: React.PointerEvent): void => {
- document.removeEventListener("pointermove", this.onBackgroundMove);
- document.removeEventListener("pointerup", this.onBackgroundUp);
- document.addEventListener("pointermove", this.onBackgroundMove);
- document.addEventListener("pointerup", this.onBackgroundUp);
- e.stopPropagation();
+ setupMoveUpEvents(this, e, this.onBackgroundMove, (e) => { }, (e) => { });
}
@action
- onBackgroundMove = (e: PointerEvent): void => {
+ onBackgroundMove = (e: PointerEvent, down: number[]): boolean => {
const dragDocView = SelectionManager.SelectedDocuments()[0];
const dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
const [left, top] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).inverse().transformPoint(0, 0);
@@ -184,200 +194,130 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
dragData.isSelectionMove = true;
this.Interacting = true;
this._hidden = true;
- document.removeEventListener("pointermove", this.onBackgroundMove);
- document.removeEventListener("pointerup", this.onBackgroundUp);
- document.removeEventListener("pointermove", this.onTitleMove);
- document.removeEventListener("pointerup", this.onTitleUp);
DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(documentView => documentView.ContentDiv!), dragData, e.x, e.y, {
dragComplete: action(e => this._hidden = this.Interacting = false),
hideSource: true
});
- e.stopPropagation();
- }
-
- @action
- onBackgroundUp = (e: PointerEvent): void => {
- document.removeEventListener("pointermove", this.onBackgroundMove);
- document.removeEventListener("pointerup", this.onBackgroundUp);
- e.stopPropagation();
- e.preventDefault();
+ return true;
}
onCloseDown = (e: React.PointerEvent): void => {
- e.stopPropagation();
- if (e.button === 0) {
- document.removeEventListener("pointermove", this.onCloseMove);
- document.addEventListener("pointermove", this.onCloseMove);
- document.removeEventListener("pointerup", this.onCloseUp);
- document.addEventListener("pointerup", this.onCloseUp);
- }
- }
- onCloseMove = (e: PointerEvent): void => {
- e.stopPropagation();
- if (e.button === 0) {
- }
+ setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onCloseClick);
}
@undoBatch
@action
- onCloseUp = async (e: PointerEvent) => {
- e.stopPropagation();
+ onCloseClick = async (e: PointerEvent) => {
if (e.button === 0) {
const recent = Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc) as Doc;
const selected = SelectionManager.SelectedDocuments().slice();
SelectionManager.DeselectAll();
+ this._addedCloseCalls.forEach(handler => handler(selected));
+
selected.map(dv => {
recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
dv.props.removeDocument && dv.props.removeDocument(dv.props.Document);
});
- document.removeEventListener("pointermove", this.onCloseMove);
- document.removeEventListener("pointerup", this.onCloseUp);
}
}
@action
onMinimizeDown = (e: React.PointerEvent): void => {
- e.stopPropagation();
- if (e.button === 0) {
- document.removeEventListener("pointermove", this.onMinimizeMove);
- document.addEventListener("pointermove", this.onMinimizeMove);
- document.removeEventListener("pointerup", this.onMinimizeUp);
- document.addEventListener("pointerup", this.onMinimizeUp);
- }
- }
-
- @action
- onMinimizeMove = (e: PointerEvent): void => {
- e.stopPropagation();
- if (Math.abs(e.pageX - this._downX) > Utils.DRAG_THRESHOLD ||
- Math.abs(e.pageY - this._downY) > Utils.DRAG_THRESHOLD) {
- document.removeEventListener("pointermove", this.onMinimizeMove);
- document.removeEventListener("pointerup", this.onMinimizeUp);
- }
+ setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onMinimizeClick);
}
@undoBatch
@action
- onMinimizeUp = (e: PointerEvent): void => {
- e.stopPropagation();
+ onMinimizeClick = (e: PointerEvent): void => {
if (e.button === 0) {
- document.removeEventListener("pointermove", this.onMinimizeMove);
- document.removeEventListener("pointerup", this.onMinimizeUp);
const selectedDocs = SelectionManager.SelectedDocuments().map(sd => sd);
selectedDocs.map(dv => {
const layoutKey = Cast(dv.props.Document.layoutKey, "string", null);
const collapse = layoutKey !== "layout_icon";
if (collapse) {
+ dv.switchViews(collapse, "icon");
if (layoutKey && layoutKey !== "layout") dv.props.Document.deiconifyLayout = layoutKey.replace("layout_", "");
- dv.setCustomView(collapse, "icon");
} else {
const deiconifyLayout = Cast(dv.props.Document.deiconifyLayout, "string", null);
- dv.setCustomView(deiconifyLayout ? true : false, deiconifyLayout);
+ dv.switchViews(deiconifyLayout ? true : false, deiconifyLayout);
dv.props.Document.deiconifyLayout = undefined;
}
});
}
+ SelectionManager.DeselectAll();
+ }
+
+ @action
+ onSelectorUp = (e: React.PointerEvent): void => {
+ setupMoveUpEvents(this, e, returnFalse, emptyFunction, action((e) => {
+ const selDoc = SelectionManager.SelectedDocuments()?.[0];
+ if (selDoc) {
+ selDoc.props.ContainingCollectionView?.props.select(false);
+ }
+ }));
}
@action
onRadiusDown = (e: React.PointerEvent): void => {
- e.stopPropagation();
+ setupMoveUpEvents(this, e, this.onRadiusMove, (e) => this._resizeUndo?.end(), (e) => { });
if (e.button === 0) {
- this._radiusDown = [e.clientX, e.clientY];
- this._isPointerDown = true;
this._resizeUndo = UndoManager.StartBatch("DocDecs set radius");
- document.removeEventListener("pointermove", this.onRadiusMove);
- document.removeEventListener("pointerup", this.onRadiusUp);
- document.addEventListener("pointermove", this.onRadiusMove);
- document.addEventListener("pointerup", this.onRadiusUp);
}
}
- onRadiusMove = (e: PointerEvent): void => {
- let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1]));
+ onRadiusMove = (e: PointerEvent, down: number[]): boolean => {
+ let dist = Math.sqrt((e.clientX - down[0]) * (e.clientX - down[0]) + (e.clientY - down[1]) * (e.clientY - down[1]));
dist = dist < 3 ? 0 : dist;
- SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplateForField ? dv.props.Document : Doc.GetProto(dv.props.Document)).
- map(d => d.borderRounding = `${Math.min(100, dist)}%`);
- e.stopPropagation();
- e.preventDefault();
- }
-
- onRadiusUp = (e: PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isPointerDown = false;
- this._resizeUndo && this._resizeUndo.end();
- document.removeEventListener("pointermove", this.onRadiusMove);
- document.removeEventListener("pointerup", this.onRadiusUp);
+ SelectionManager.SelectedDocuments().map(dv => dv.props.Document).map(doc => doc.layout instanceof Doc ? doc.layout : doc.isTemplateForField ? doc : Doc.GetProto(doc)).
+ map(d => d.borderRounding = `${Math.max(0, dist)}px`);
+ return false;
}
- _lastX = 0;
- _lastY = 0;
@action
onPointerDown = (e: React.PointerEvent): void => {
- e.stopPropagation();
+ setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, (e) => { });
if (e.button === 0) {
- this._lastX = e.clientX;
- this._lastY = e.clientY;
- this._isPointerDown = true;
- this._resizing = e.currentTarget.id;
+ this._resizeHdlId = e.currentTarget.id;
this.Interacting = true;
this._resizeUndo = UndoManager.StartBatch("DocDecs resize");
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
}
}
-
- onPointerMove = (e: PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- if (!this._isPointerDown) {
- return;
- }
-
+ onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => {
let dX = 0, dY = 0, dW = 0, dH = 0;
- const moveX = e.clientX - this._lastX; // e.movementX;
- const moveY = e.clientY - this._lastY; // e.movementY;
- this._lastX = e.clientX;
- this._lastY = e.clientY;
-
- switch (this._resizing) {
- case "":
- break;
+ switch (this._resizeHdlId) {
+ case "": break;
case "documentDecorations-topLeftResizer":
dX = -1;
dY = -1;
- dW = -moveX;
- dH = -moveY;
+ dW = -move[0];
+ dH = -move[1];
break;
case "documentDecorations-topRightResizer":
- dW = moveX;
+ dW = move[0];
dY = -1;
- dH = -moveY;
+ dH = -move[1];
break;
case "documentDecorations-topResizer":
dY = -1;
- dH = -moveY;
+ dH = -move[1];
break;
case "documentDecorations-bottomLeftResizer":
dX = -1;
- dW = -moveX;
- dH = moveY;
+ dW = -move[0];
+ dH = move[1];
break;
case "documentDecorations-bottomRightResizer":
- dW = moveX;
- dH = moveY;
+ dW = move[0];
+ dH = move[1];
break;
case "documentDecorations-bottomResizer":
- dH = moveY;
+ dH = move[1];
break;
case "documentDecorations-leftResizer":
dX = -1;
- dW = -moveX;
+ dW = -move[0];
break;
case "documentDecorations-rightResizer":
- dW = moveX;
+ dW = move[0];
break;
}
@@ -390,21 +330,31 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
const width = (layoutDoc._width || 0);
const height = (layoutDoc._height || (nheight / nwidth * width));
const scale = element.props.ScreenToLocalTransform().Scale * element.props.ContentScaling();
+ if (nwidth && nheight) {
+ if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth;
+ else dW = dH * nwidth / nheight;
+ }
const actualdW = Math.max(width + (dW * scale), 20);
const actualdH = Math.max(height + (dH * scale), 20);
doc.x = (doc.x || 0) + dX * (actualdW - width);
doc.y = (doc.y || 0) + dY * (actualdH - height);
- const fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight);
- if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) {
- layoutDoc.ignoreAspect = false;
- layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0;
- layoutDoc._nativeHeight = nheight = layoutDoc._height || 0;
- }
+ const fixedAspect = (nwidth && nheight);
if (fixedAspect && (!nwidth || !nheight)) {
layoutDoc._nativeWidth = nwidth = layoutDoc._width || 0;
layoutDoc._nativeHeight = nheight = layoutDoc._height || 0;
}
- if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) {
+ const anno = Cast(doc.annotationOn, Doc, null);
+ if (e.ctrlKey && anno) {
+ dW !== 0 && runInAction(() => {
+ const dataDoc = anno[DataSym];
+ const fieldKey = Doc.LayoutFieldKey(anno);
+ const nw = NumCast(dataDoc[fieldKey + "-nativeWidth"]);
+ const nh = NumCast(dataDoc[fieldKey + "-nativeHeight"]);
+ dataDoc[fieldKey + "-nativeWidth"] = nw + (dW > 0 ? 10 : -10);
+ dataDoc[fieldKey + "-nativeHeight"] = nh + (dW > 0 ? 10 : -10) * nh / nw;
+ });
+ }
+ else if (nwidth > 0 && nheight > 0) {
if (Math.abs(dW) > Math.abs(dH)) {
if (!fixedAspect) {
layoutDoc._nativeWidth = actualdW / (layoutDoc._width || 1) * (layoutDoc._nativeWidth || 0);
@@ -428,20 +378,15 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
}
}));
+ return false;
}
@action
onPointerUp = (e: PointerEvent): void => {
- e.stopPropagation();
- this._resizing = "";
+ this._resizeHdlId = "";
this.Interacting = false;
- if (e.button === 0) {
- e.preventDefault();
- this._isPointerDown = false;
- this._resizeUndo && this._resizeUndo.end();
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- }
+ (e.button === 0) && this._resizeUndo?.end();
+ this._resizeUndo = undefined;
}
@computed
@@ -467,17 +412,54 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
this.TextBar = ele;
}
}
+ public static DocumentIcon(layout: string) {
+ const button = layout.indexOf("PDFBox") !== -1 ? faFilePdf :
+ layout.indexOf("ImageBox") !== -1 ? faImage :
+ layout.indexOf("Formatted") !== -1 ? faStickyNote :
+ layout.indexOf("Video") !== -1 ? faFilm :
+ layout.indexOf("Collection") !== -1 ? faObjectGroup :
+ faCaretUp;
+ return <FontAwesomeIcon icon={button} className="documentView-minimizedIcon" />;
+ }
render() {
+ const darkScheme = Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "dimgray" : undefined;
const bounds = this.Bounds;
const seldoc = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0] : undefined;
- if (SelectionManager.GetIsDragging() || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) {
+ if (SelectionManager.GetIsDragging() || bounds.r - bounds.x < 2 || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) {
return (null);
}
- const minimizeIcon = (
- <div className="documentDecorations-minimizeButton" onPointerDown={this.onMinimizeDown}>
- {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
- {SelectionManager.SelectedDocuments().length === 1 ? IconBox.DocumentIcon(StrCast(SelectionManager.SelectedDocuments()[0].props.Document.layout, "...")) : "..."}
- </div>);
+ const minimal = bounds.r - bounds.x < 100 ? true : false;
+ const minimizeIcon = minimal ? (
+ <div className="documentDecorations-contextMenu" title="Show context menu" onPointerDown={this.onSettingsDown}>
+ <FontAwesomeIcon size="lg" icon="cog" />
+ </div>) : (
+ <div className="documentDecorations-minimizeButton" title="Iconify" onPointerDown={this.onMinimizeDown}>
+ {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
+ {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
+ </div>);
+
+ const titleArea = this._edtingTitle ?
+ <>
+ <input ref={this._keyinput} className="documentDecorations-title" type="text" name="dynbox" autoComplete="on" value={this._accumulatedTitle} style={{ width: minimal ? "100%" : "calc(100% - 20px)" }}
+ onBlur={e => this.titleBlur(true)} onChange={action(e => this._accumulatedTitle = e.target.value)} onKeyPress={this.titleEntered} />
+ {minimal ? (null) : <div className="publishBox" title="make document referenceable by its title"
+ onPointerDown={action(e => {
+ if (!seldoc.props.Document.customTitle) {
+ seldoc.props.Document.customTitle = true;
+ StrCast(Doc.GetProto(seldoc.props.Document).title).startsWith("-") && (Doc.GetProto(seldoc.props.Document).title = StrCast(seldoc.props.Document.title).substring(1));
+ this._accumulatedTitle = StrCast(seldoc.props.Document.title);
+ }
+ DocUtils.Publish(seldoc.props.Document, this._accumulatedTitle, seldoc.props.addDocument, seldoc.props.removeDocument);
+ })}>
+ <FontAwesomeIcon size="lg" color={SelectionManager.SelectedDocuments()[0].props.Document.title === SelectionManager.SelectedDocuments()[0].props.Document[Id] ? "green" : undefined} icon="sticky-note"></FontAwesomeIcon>
+ </div>}
+ </> :
+ <div className="documentDecorations-title" onPointerDown={this.onTitleDown} >
+ {minimal ? (null) : <div className="documentDecorations-contextMenu" title="Show context menu" onPointerDown={this.onSettingsDown}>
+ <FontAwesomeIcon size="lg" icon="cog" />
+ </div>}
+ <span style={{ width: "calc(100% - 25px)", display: "inline-block" }}>{`${this.selectionTitle}`}</span>
+ </div>;
bounds.x = Math.max(0, bounds.x - this._resizeBorderWidth / 2) + this._resizeBorderWidth / 2;
bounds.y = Math.max(0, bounds.y - this._resizeBorderWidth / 2 - this._titleHeight) + this._resizeBorderWidth / 2 + this._titleHeight;
@@ -490,7 +472,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (bounds.y > bounds.b) {
bounds.y = bounds.b - (this._resizeBorderWidth + this._linkBoxHeight + this._titleHeight);
}
- return (<div className="documentDecorations">
+ return (<div className="documentDecorations" style={{ background: darkScheme }} >
<div className="documentDecorations-background" style={{
width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
height: (bounds.b - bounds.y + this._resizeBorderWidth) + "px",
@@ -498,38 +480,48 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
top: bounds.y - this._resizeBorderWidth / 2,
pointerEvents: this.Interacting ? "none" : "all",
zIndex: SelectionManager.SelectedDocuments().length > 1 ? 900 : 0,
- }} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); }} >
+ }} onPointerDown={this.onBackgroundDown} onContextMenu={e => { e.preventDefault(); e.stopPropagation(); }} >
</div>
<div className="documentDecorations-container" ref={this.setTextBar} style={{
width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
- height: (bounds.b - bounds.y + this._resizeBorderWidth + this._linkBoxHeight + this._titleHeight + 3) + "px",
+ height: (bounds.b - bounds.y + this._resizeBorderWidth + this._titleHeight) + "px",
left: bounds.x - this._resizeBorderWidth / 2,
top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
- opacity: this._opacity
}}>
{minimizeIcon}
-
- {this._edtingTitle ?
- <input ref={this._keyinput} className="title" type="text" name="dynbox" value={this._accumulatedTitle} onBlur={e => this.titleBlur(true)} onChange={this.titleChanged} onKeyPress={this.titleEntered} /> :
- <div className="title" onPointerDown={this.onTitleDown} ><span>{`${this.selectionTitle}`}</span></div>}
+ {titleArea}
<div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>
<FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
</div>
- <div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-topResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-topRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-leftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer"
+ onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-topResizer" className="documentDecorations-resizer"
+ onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-topRightResizer" className="documentDecorations-resizer"
+ onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-leftResizer" className="documentDecorations-resizer"
+ onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
<div id="documentDecorations-centerCont"></div>
- <div id="documentDecorations-rightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-bottomLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-bottomResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-bottomRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
- <div id="documentDecorations-borderRadius" className="documentDecorations-radius" onPointerDown={this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}><span className="borderRadiusTooltip" title="Drag Corner Radius"></span></div>
- <div className="link-button-container">
- <DocumentButtonBar views={SelectionManager.SelectedDocuments()} />
- </div>
+ <div id="documentDecorations-rightResizer" className="documentDecorations-resizer"
+ onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-bottomLeftResizer" className="documentDecorations-resizer"
+ onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-bottomResizer" className="documentDecorations-resizer"
+ onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id="documentDecorations-bottomRightResizer" className="documentDecorations-resizer"
+ onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+ {seldoc.props.renderDepth <= 1 || !seldoc.props.ContainingCollectionView ? (null) : <div id="documentDecorations-levelSelector" className="documentDecorations-selector" title="tap to select containing document"
+ onPointerDown={this.onSelectorUp} onContextMenu={(e) => e.preventDefault()}>
+ <FontAwesomeIcon className="documentdecorations-times" icon={faArrowAltCircleUp} size="lg" />
+ </div>}
+ <div id="documentDecorations-borderRadius" className="documentDecorations-radius"
+ onPointerDown={this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}></div>
+
</div >
- </div>
+ <div className="link-button-container" style={{ left: bounds.x - this._resizeBorderWidth / 2, top: bounds.b + this._resizeBorderWidth / 2 }}>
+ <DocumentButtonBar views={SelectionManager.SelectedDocuments()} />
+ </div>
+ </div >
);
}
} \ No newline at end of file