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.tsx171
1 files changed, 135 insertions, 36 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 2c0e18bbb..fb5104915 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,18 +1,18 @@
import { library } from '@fortawesome/fontawesome-svg-core';
-import { faLink } from '@fortawesome/free-solid-svg-icons';
+import { faLink, faTag } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { Doc } from "../../new_fields/Doc";
import { List } from "../../new_fields/List";
-import { listSpec } from "../../new_fields/Schema";
-import { Cast, NumCast, StrCast, BoolCast } from "../../new_fields/Types";
+import { BoolCast, Cast, NumCast, StrCast } from "../../new_fields/Types";
+import { URLField } from '../../new_fields/URLField';
import { emptyFunction, Utils } from "../../Utils";
import { Docs } from "../documents/Documents";
import { DocumentManager } from "../util/DocumentManager";
import { DragLinksAsDocuments, DragManager } from "../util/DragManager";
import { SelectionManager } from "../util/SelectionManager";
-import { undoBatch } from "../util/UndoManager";
+import { undoBatch, UndoManager } from "../util/UndoManager";
import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss";
import { CollectionView } from "./collections/CollectionView";
import './DocumentDecorations.scss';
@@ -24,12 +24,16 @@ import { LinkMenu } from "./nodes/LinkMenu";
import { TemplateMenu } from "./TemplateMenu";
import { Template, Templates } from "./Templates";
import React = require("react");
-import { URLField } from '../../new_fields/URLField';
+import { RichTextField } from '../../new_fields/RichTextField';
+import { LinkManager } from '../util/LinkManager';
+import { ObjectField } from '../../new_fields/ObjectField';
+import { MetadataEntryMenu } from './MetadataEntryMenu';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
library.add(faLink);
+library.add(faTag);
@observer
export class DocumentDecorations extends React.Component<{}, { value: string }> {
@@ -43,9 +47,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
private _linkButton = React.createRef<HTMLDivElement>();
private _linkerButton = React.createRef<HTMLDivElement>();
private _embedButton = React.createRef<HTMLDivElement>();
+ private _tooltipoff = React.createRef<HTMLDivElement>();
+ private _textDoc?: Doc;
private _downX = 0;
private _downY = 0;
private _iconDoc?: Doc = undefined;
+ private _resizeUndo?: UndoManager.Batch;
@observable private _minimizedX = 0;
@observable private _minimizedY = 0;
@observable private _title: string = "";
@@ -73,6 +80,13 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (text[0] === '#') {
this._fieldKey = text.slice(1, text.length);
this._title = this.selectionTitle;
+ } else if (text.startsWith(">")) {
+ let fieldTemplateView = SelectionManager.SelectedDocuments()[0];
+ SelectionManager.DeselectAll();
+ let fieldTemplate = fieldTemplateView.props.Document;
+ let docTemplate = fieldTemplateView.props.ContainingCollectionView!.props.Document;
+ let metaKey = text.slice(1, text.length);
+ Doc.MakeTemplate(fieldTemplate, metaKey, Doc.GetProto(docTemplate));
}
else {
if (SelectionManager.SelectedDocuments().length > 0) {
@@ -122,7 +136,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
@computed
get Bounds(): { x: number, y: number, b: number, r: number } {
return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
- if (documentView.props.isTopMost) {
+ if (documentView.props.renderDepth === 0) {
return bounds;
}
let transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
@@ -141,7 +155,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
document.addEventListener("pointermove", this.onBackgroundMove);
document.addEventListener("pointerup", this.onBackgroundUp);
e.stopPropagation();
- e.preventDefault();
}
@action
@@ -149,7 +162,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
let dragDocView = SelectionManager.SelectedDocuments()[0];
const [left, top] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).inverse().transformPoint(0, 0);
const [xoff, yoff] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).transformDirection(e.x - left, e.y - top);
- let dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
+ let dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document), SelectionManager.SelectedDocuments().map(dv => dv.props.DataDoc ? dv.props.DataDoc : dv.props.Document));
dragData.xOffset = xoff;
dragData.yOffset = yoff;
dragData.moveDocument = SelectionManager.SelectedDocuments()[0].props.moveDocument;
@@ -275,7 +288,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
@undoBatch
@action createIcon = (selected: DocumentView[], layoutString: string): Doc => {
let doc = selected[0].props.Document;
- let iconDoc = Docs.IconDocument(layoutString);
+ let iconDoc = Docs.Create.IconDocument(layoutString);
iconDoc.isButton = true;
iconDoc.proto!.title = selected.length > 1 ? "-multiple-.icon" : StrCast(doc.title) + ".icon";
iconDoc.labelField = selected.length > 1 ? undefined : this._fieldKey;
@@ -310,6 +323,37 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
iconDoc.y = where[1] + NumCast(selView.props.Document.y);
}
+ _radiusDown = [0, 0];
+ @action
+ onRadiusDown = (e: React.PointerEvent): void => {
+ e.stopPropagation();
+ 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]));
+ SelectionManager.SelectedDocuments().map(dv => dv.props.Document.borderRounding = Doc.GetProto(dv.props.Document).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);
+ }
+
@action
onPointerDown = (e: React.PointerEvent): void => {
e.stopPropagation();
@@ -317,6 +361,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
this._isPointerDown = true;
this._resizing = 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);
@@ -408,7 +453,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (this._linkButton.current !== null && (e.movementX > 1 || e.movementY > 1)) {
document.removeEventListener("pointermove", this.onLinkButtonMoved);
document.removeEventListener("pointerup", this.onLinkButtonUp);
-
DragLinksAsDocuments(this._linkButton.current, e.x, e.y, SelectionManager.SelectedDocuments()[0].props.Document);
}
e.stopPropagation();
@@ -468,10 +512,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
let doc = PositionDocument(element.props.Document);
let nwidth = doc.nativeWidth || 0;
let nheight = doc.nativeHeight || 0;
- let zoomBasis = NumCast(doc.zoomBasis, 1);
- let width = (doc.width || 0) / zoomBasis;
- let height = (doc.height || (nheight / nwidth * width)) / zoomBasis;
- let scale = element.props.ScreenToLocalTransform().Scale;
+ let width = (doc.width || 0);
+ let height = (doc.height || (nheight / nwidth * width));
+ let scale = element.props.ScreenToLocalTransform().Scale * element.props.ContentScaling();
let actualdW = Math.max(width + (dW * scale), 20);
let actualdH = Math.max(height + (dH * scale), 20);
doc.x = (doc.x || 0) + dX * (actualdW - width);
@@ -485,25 +528,25 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
if (nwidth > 0 && nheight > 0) {
if (Math.abs(dW) > Math.abs(dH)) {
- if (!fixedAspect) proto.nativeWidth = zoomBasis * actualdW / (doc.width || 1) * NumCast(proto.nativeWidth);
- doc.width = zoomBasis * actualdW;
- // doc.zoomBasis = zoomBasis * width / actualdW;
+ if (!fixedAspect) {
+ Doc.SetInPlace(element.props.Document, "nativeWidth", actualdW / (doc.width || 1) * (doc.nativeWidth || 0), true);
+ }
+ doc.width = actualdW;
if (fixedAspect) doc.height = nheight / nwidth * doc.width;
- else doc.height = zoomBasis * actualdH;
- proto.nativeHeight = (doc.height || 0) / doc.width * NumCast(proto.nativeWidth);
+ else doc.height = actualdH;
}
else {
- if (!fixedAspect) proto.nativeHeight = zoomBasis * actualdH / (doc.height || 1) * NumCast(proto.nativeHeight);
- doc.height = zoomBasis * actualdH;
- //doc.zoomBasis = zoomBasis * height / actualdH;
+ if (!fixedAspect) {
+ Doc.SetInPlace(element.props.Document, "nativeHeight", actualdH / (doc.height || 1) * (doc.nativeHeight || 0), true);
+ }
+ doc.height = actualdH;
if (fixedAspect) doc.width = nwidth / nheight * doc.height;
- else doc.width = zoomBasis * actualdW;
- proto.nativeWidth = (doc.width || 0) / doc.height * NumCast(proto.nativeHeight);
+ else doc.width = actualdW;
}
} else {
- dW && (doc.width = zoomBasis * actualdW);
- dH && (doc.height = zoomBasis * actualdH);
- proto.autoHeight = undefined;
+ dW && (doc.width = actualdW);
+ dH && (doc.height = actualdH);
+ Doc.SetInPlace(element.props.Document, "autoHeight", undefined, true);
}
}
});
@@ -517,6 +560,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (e.button === 0) {
e.preventDefault();
this._isPointerDown = false;
+ this._resizeUndo && this._resizeUndo.end();
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
}
@@ -551,10 +595,51 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (!canEmbed) return (null);
return (
<div className="linkButtonWrapper">
- <div style={{ paddingTop: 3, marginLeft: 30 }} title="Drag Embed" className="linkButton-linker" ref={this._embedButton} onPointerDown={this.onEmbedButtonDown}>
- <FontAwesomeIcon className="fa-image" icon="image" size="sm" />
+ <div title="Drag Embed" className="linkButton-linker" ref={this._embedButton} onPointerDown={this.onEmbedButtonDown}>
+ <FontAwesomeIcon className="documentdecorations-icon" icon="image" size="sm" />
+ </div>
+ </div>
+ );
+ }
+
+ considerTooltip = () => {
+ let thisDoc = SelectionManager.SelectedDocuments()[0].props.Document;
+ let isTextDoc = thisDoc.data && thisDoc.data instanceof RichTextField;
+ if (!isTextDoc) return null;
+ this._textDoc = thisDoc;
+ return (
+ <div className="tooltipwrapper">
+ <div title="Hide Tooltip" className="linkButton-linker" ref={this._tooltipoff} onPointerDown={this.onTooltipOff}>
+ {/* <FontAwesomeIcon className="fa-image" icon="image" size="sm" /> */}
</div>
</div>
+
+ );
+ }
+
+ onTooltipOff = (e: React.PointerEvent): void => {
+ e.stopPropagation();
+ if (this._textDoc) {
+ if (this._tooltipoff.current) {
+ if (this._tooltipoff.current.title === "Hide Tooltip") {
+ this._tooltipoff.current.title = "Show Tooltip";
+ this._textDoc.tooltip = "hi";
+ }
+ else {
+ this._tooltipoff.current.title = "Hide Tooltip";
+ }
+ }
+ }
+ }
+
+ get metadataMenu() {
+ return (
+ <div className="linkButtonWrapper">
+ <Flyout anchorPoint={anchorPoints.TOP_LEFT}
+ content={<MetadataEntryMenu docs={() => SelectionManager.SelectedDocuments().map(dv => dv.props.Document)} suggestWithFunction />}>{/* tfs: @bcz This might need to be the data document? */}
+ <div className="docDecs-tagButton" title="Add fields"><FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" /></div>
+ </Flyout>
+ </div>
);
}
@@ -572,9 +657,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
let linkButton = null;
if (SelectionManager.SelectedDocuments().length > 0) {
let selFirst = SelectionManager.SelectedDocuments()[0];
- let linkToSize = Cast(selFirst.props.Document.linkedToDocs, listSpec(Doc), []).length;
- let linkFromSize = Cast(selFirst.props.Document.linkedFromDocs, listSpec(Doc), []).length;
- let linkCount = linkToSize + linkFromSize;
+ let linkCount = LinkManager.Instance.getAllRelatedLinks(selFirst.props.Document).length;
linkButton = (<Flyout
anchorPoint={anchorPoints.RIGHT_TOP}
content={<LinkMenu docView={selFirst}
@@ -610,6 +693,17 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
templates.set(template, checked);
});
+ 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;
+ const borderRadiusDraggerWidth = 15;
+ bounds.r = Math.min(window.innerWidth, bounds.r + borderRadiusDraggerWidth + this._resizeBorderWidth / 2) - this._resizeBorderWidth / 2 - borderRadiusDraggerWidth;
+ bounds.b = Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight;
+ if (bounds.x > bounds.r) {
+ bounds.x = bounds.r - this._resizeBorderWidth;
+ }
+ if (bounds.y > bounds.b) {
+ bounds.y = bounds.b - (this._resizeBorderWidth + this._linkBoxHeight + this._titleHeight);
+ }
return (<div className="documentDecorations">
<div className="documentDecorations-background" style={{
width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
@@ -617,7 +711,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
left: bounds.x - this._resizeBorderWidth / 2,
top: bounds.y - this._resizeBorderWidth / 2,
pointerEvents: this.Interacting ? "none" : "all",
- zIndex: SelectionManager.SelectedDocuments().length > 1 ? 1000 : 0,
+ zIndex: SelectionManager.SelectedDocuments().length > 1 ? 900 : 0,
}} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); }} >
</div>
<div className="documentDecorations-container" style={{
@@ -632,7 +726,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
{this._edtingTitle ?
<input ref={this.keyinput} className="title" type="text" name="dynbox" value={this._title} onBlur={this.titleBlur} onChange={this.titleChanged} onKeyPress={this.titleEntered} /> :
<div className="title" onPointerDown={this.onTitleDown} ><span>{`${this.selectionTitle}`}</span></div>}
- <div className="documentDecorations-closeButton" onPointerDown={this.onCloseDown}>X</div>
+ <div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>X</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>
@@ -642,17 +736,22 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
<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">
<div className="linkButtonWrapper">
<div title="View Links" className="linkFlyout" ref={this._linkButton}> {linkButton} </div>
</div>
<div className="linkButtonWrapper">
<div title="Drag Link" className="linkButton-linker" ref={this._linkerButton} onPointerDown={this.onLinkerButtonDown}>
- <FontAwesomeIcon className="fa-icon-link" icon="link" size="sm" />
+ <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" />
</div>
</div>
- <TemplateMenu docs={SelectionManager.ViewsSortedVertically()} templates={templates} />
+ <div className="linkButtonWrapper">
+ <TemplateMenu docs={SelectionManager.ViewsSortedVertically()} templates={templates} />
+ </div>
+ {this.metadataMenu}
{this.considerEmbed()}
+ {/* {this.considerTooltip()} */}
</div>
</div >
</div>