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.tsx45
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx32
-rw-r--r--src/client/views/nodes/DocumentView.scss9
-rw-r--r--src/client/views/nodes/DocumentView.tsx258
-rw-r--r--src/client/views/nodes/FieldView.tsx10
-rw-r--r--src/client/views/nodes/FormattedTextBox.scss6
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx86
-rw-r--r--src/client/views/nodes/ImageBox.scss12
-rw-r--r--src/client/views/nodes/ImageBox.tsx87
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx6
-rw-r--r--src/client/views/nodes/KeyValuePair.scss40
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx47
-rw-r--r--src/client/views/nodes/WebBox.scss6
-rw-r--r--src/client/views/nodes/WebBox.tsx35
14 files changed, 328 insertions, 351 deletions
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 77f41105f..8cf7a0dd2 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,4 +1,4 @@
-import { computed } from "mobx";
+import { computed, trace } from "mobx";
import { observer } from "mobx-react";
import { KeyStore } from "../../../fields/KeyStore";
import { NumberField } from "../../../fields/NumberField";
@@ -6,28 +6,21 @@ import { Transform } from "../../util/Transform";
import { DocumentView, DocumentViewProps } from "./DocumentView";
import "./DocumentView.scss";
import React = require("react");
-import { thisExpression } from "babel-types";
+import { OmitKeys } from "../../../Utils";
+export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
+}
@observer
-export class CollectionFreeFormDocumentView extends React.Component<DocumentViewProps> {
+export class CollectionFreeFormDocumentView extends React.Component<CollectionFreeFormDocumentViewProps> {
private _mainCont = React.createRef<HTMLDivElement>();
- constructor(props: DocumentViewProps) {
- super(props);
- }
- get screenRect(): ClientRect | DOMRect {
- if (this._mainCont.current) {
- return this._mainCont.current.getBoundingClientRect();
- }
- return new DOMRect();
- }
-
@computed
get transform(): string {
- return `scale(${this.props.ContentScaling()}, ${this.props.ContentScaling()}) translate(${this.props.Document.GetNumber(KeyStore.X, 0)}px, ${this.props.Document.GetNumber(KeyStore.Y, 0)}px)`;
+ return `scale(${this.props.ContentScaling()}, ${this.props.ContentScaling()}) translate(${this.props.Document.GetNumber(KeyStore.X, 0)}px, ${this.props.Document.GetNumber(KeyStore.Y, 0)}px) scale(${this.zoom}, ${this.zoom}) `;
}
+ @computed get zoom(): number { return 1 / this.props.Document.GetNumber(KeyStore.Zoom, 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(); }
@@ -52,28 +45,40 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
this.props.Document.SetData(KeyStore.ZIndex, h, NumberField);
}
- contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1;
-
getTransform = (): Transform =>
this.props.ScreenToLocalTransform()
.translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0))
- .scale(1 / this.contentScaling())
+ .scale(1 / this.contentScaling()).scale(1 / this.zoom)
+
+ contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1;
+ panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth();
+ panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight();
@computed
get docView() {
- return <DocumentView {...this.props}
+ return <DocumentView {...OmitKeys(this.props, ['zoomFade'])}
ContentScaling={this.contentScaling}
ScreenToLocalTransform={this.getTransform}
PanelWidth={this.panelWidth}
PanelHeight={this.panelHeight}
/>;
}
- panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth();
- panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight();
render() {
+ let zoomFade = 1;
+ // //var zoom = doc.GetNumber(KeyStore.Zoom, 1);
+ // let transform = (this.props.ScreenToLocalTransform().scale(this.props.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;
+
return (
<div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
+ opacity: zoomFade,
transformOrigin: "left top",
transform: this.transform,
pointerEvents: "all",
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 5836da396..76f852601 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -23,7 +23,7 @@ import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
import React = require("react");
import { Document } from "../../../fields/Document";
import { FieldViewProps } from "./FieldView";
-import { Without } from "../../../Utils";
+import { Without, OmitKeys } from "../../../Utils";
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
type BindingProps = Without<FieldViewProps, 'fieldKey'>;
@@ -44,34 +44,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
CreateBindings(): JsxBindings {
- let
- {
- Document,
- isSelected,
- select,
- isTopMost,
- selectOnLoad,
- ScreenToLocalTransform,
- addDocument,
- removeDocument,
- onActiveChanged,
- parentActive: active,
- } = this.props;
- let bindings: JsxBindings = {
- props: {
- Document,
- isSelected,
- select,
- isTopMost,
- selectOnLoad,
- ScreenToLocalTransform,
- active,
- onActiveChanged,
- addDocument,
- removeDocument,
- focus,
- }
- };
+ let bindings: JsxBindings = { props: OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive) };
+
for (const key of this.layoutKeys) {
bindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data
}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index a946ac1a8..690ee50e8 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,10 +1,11 @@
@import "../globalCssVariables";
-.documentView-node {
+.documentView-node, .documentView-node-topmost {
position: inherit;
top: 0;
left:0;
background: $light-color; //overflow: hidden;
+ transform-origin: left top;
&.minimized {
width: 30px;
@@ -28,12 +29,16 @@
height: calc(100% - 20px);
}
}
+.documentView-node-topmost {
+ background: white;
+}
.minimized-box {
height: 10px;
width: 10px;
border-radius: 2px;
- background: $dark-color
+ background: $dark-color;
+ transform-origin: left top;
}
.minimized-box:hover {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 4d7a85316..b99e449be 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,30 +1,32 @@
-import { action, computed, IReactionDisposer, reaction, runInAction, trace } from "mobx";
+import { action, computed, runInAction } from "mobx";
import { observer } from "mobx-react";
+import { BooleanField } from "../../../fields/BooleanField";
import { Document } from "../../../fields/Document";
import { Field, FieldWaiting, Opt } from "../../../fields/Field";
import { Key } from "../../../fields/Key";
import { KeyStore } from "../../../fields/KeyStore";
import { ListField } from "../../../fields/ListField";
-import { BooleanField } from "../../../fields/BooleanField";
import { TextField } from "../../../fields/TextField";
import { ServerUtils } from "../../../server/ServerUtil";
-import { Utils, emptyFunction } from "../../../Utils";
+import { emptyFunction, Utils } from "../../../Utils";
import { Documents } from "../../documents/Documents";
import { DocumentManager } from "../../util/DocumentManager";
import { DragManager } from "../../util/DragManager";
import { SelectionManager } from "../../util/SelectionManager";
import { Transform } from "../../util/Transform";
+import { undoBatch, UndoManager } from "../../util/UndoManager";
import { CollectionDockingView } from "../collections/CollectionDockingView";
+import { CollectionPDFView } from "../collections/CollectionPDFView";
+import { CollectionVideoView } from "../collections/CollectionVideoView";
import { CollectionView } from "../collections/CollectionView";
import { ContextMenu } from "../ContextMenu";
import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
import React = require("react");
-import { undoBatch, UndoManager } from "../../util/UndoManager";
export interface DocumentViewProps {
- ContainingCollectionView: Opt<CollectionView>;
+ ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
Document: Document;
addDocument?: (doc: Document, allowDuplicates?: boolean) => boolean;
removeDocument?: (doc: Document) => boolean;
@@ -63,14 +65,12 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
let Keys: { [name: string]: any } = {};
let Fields: { [name: string]: any } = {};
for (const key of keys) {
- let fn = emptyFunction;
- Object.defineProperty(fn, "name", { value: key + "Key" });
- Keys[key] = fn;
+ Object.defineProperty(emptyFunction, "name", { value: key + "Key" });
+ Keys[key] = emptyFunction;
}
for (const field of fields) {
- let fn = emptyFunction;
- Object.defineProperty(fn, "name", { value: field });
- Fields[field] = fn;
+ Object.defineProperty(emptyFunction, "name", { value: field });
+ Fields[field] = emptyFunction;
}
let args: JsxArgs = {
Document: function Document() { },
@@ -83,21 +83,24 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
@observer
export class DocumentView extends React.Component<DocumentViewProps> {
- private _mainCont = React.createRef<HTMLDivElement>();
- public get ContentRef() {
- return this._mainCont;
- }
private _downX: number = 0;
private _downY: number = 0;
+ private _mainCont = React.createRef<HTMLDivElement>();
+ private _dropDisposer?: DragManager.DragDropDisposer;
+
+ public get ContentDiv() { return this._mainCont.current; }
@computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); }
@computed get topMost(): boolean { return this.props.isTopMost; }
@computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); }
@computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array<Key>()); }
@computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array<Key>()); }
- 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);
@@ -116,11 +119,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
}
- private dropDisposer?: DragManager.DragDropDisposer;
-
componentDidMount() {
if (this._mainCont.current) {
- this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
+ this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
handlers: { drop: this.drop.bind(this) }
});
}
@@ -128,29 +129,26 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
componentDidUpdate() {
- if (this.dropDisposer) {
- this.dropDisposer();
+ if (this._dropDisposer) {
+ this._dropDisposer();
}
if (this._mainCont.current) {
- this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
+ this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
handlers: { drop: this.drop.bind(this) }
});
}
}
componentWillUnmount() {
- if (this.dropDisposer) {
- this.dropDisposer();
+ if (this._dropDisposer) {
+ this._dropDisposer();
}
runInAction(() => DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1));
}
startDragging(x: number, y: number, dropAliasOfDraggedDoc: boolean) {
if (this._mainCont.current) {
- const [left, top] = this.props
- .ScreenToLocalTransform()
- .inverse()
- .transformPoint(0, 0);
+ const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
let dragData = new DragManager.DocumentDragData([this.props.Document]);
dragData.aliasOnDrop = dropAliasOfDraggedDoc;
dragData.xOffset = x - left;
@@ -169,10 +167,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
if (e.cancelBubble) {
return;
}
- if (
- Math.abs(this._downX - e.clientX) > 3 ||
- Math.abs(this._downY - e.clientY) > 3
- ) {
+ 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 (!this.topMost || e.buttons === 2 || e.altKey) {
@@ -186,22 +181,17 @@ export class DocumentView extends React.Component<DocumentViewProps> {
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
- ) {
+ if (!SelectionManager.IsSelected(this) && e.button !== 2 &&
+ Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) {
SelectionManager.SelectDoc(this, e.ctrlKey);
}
}
- stopPropogation = (e: React.SyntheticEvent) => {
+ stopPropagation = (e: React.SyntheticEvent) => {
e.stopPropagation();
}
deleteClicked = (): void => {
- if (this.props.removeDocument) {
- this.props.removeDocument(this.props.Document);
- }
+ this.props.removeDocument && this.props.removeDocument(this.props.Document);
}
fieldsClicked = (e: React.MouseEvent): void => {
@@ -210,32 +200,22 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
}
fullScreenClicked = (e: React.MouseEvent): void => {
- CollectionDockingView.Instance.OpenFullScreen(this.props.Document);
+ CollectionDockingView.Instance.OpenFullScreen((this.props.Document.GetPrototype() as Document).MakeDelegate());
ContextMenu.Instance.clearItems();
- ContextMenu.Instance.addItem({
- description: "Close Full Screen",
- event: this.closeFullScreenClicked
- });
+ 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();
- ContextMenu.Instance.addItem({
- description: "Full Screen",
- event: this.fullScreenClicked
- });
+ ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked });
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
}
@action
public minimize = (): void => {
- this.props.Document.SetData(
- KeyStore.Minimized,
- true as boolean,
- BooleanField
- );
+ this.props.Document.SetBoolean(KeyStore.Minimized, true);
SelectionManager.DeselectAll();
}
@@ -251,9 +231,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
sourceDoc.GetTAsync(KeyStore.Prototype, Document).then(protoSrc =>
runInAction(() => {
let batch = UndoManager.StartBatch("document view drop");
- linkDoc.Set(KeyStore.Title, new TextField("New Link"));
- linkDoc.Set(KeyStore.LinkDescription, new TextField(""));
- linkDoc.Set(KeyStore.LinkTags, new TextField("Default"));
+ 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;
@@ -284,11 +264,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
onDrop = (e: React.DragEvent) => {
- if (e.isDefaultPrevented()) {
- return;
- }
let text = e.dataTransfer.getData("text/plain");
- if (text && text.startsWith("<div")) {
+ if (!e.isDefaultPrevented() && text && text.startsWith("<div")) {
let oldLayout = this.props.Document.GetText(KeyStore.Layout, "");
let layout = text.replace("{layout}", oldLayout);
this.props.Document.SetText(KeyStore.Layout, layout);
@@ -300,145 +277,58 @@ export class DocumentView extends React.Component<DocumentViewProps> {
@action
onContextMenu = (e: React.MouseEvent): void => {
e.stopPropagation();
- let moved =
- Math.abs(this._downX - e.clientX) > 3 ||
- Math.abs(this._downY - e.clientY) > 3;
- if (moved || e.isDefaultPrevented()) {
+ if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3 ||
+ e.isDefaultPrevented()) {
e.preventDefault();
return;
}
e.preventDefault();
- if (!this.isMinimized()) {
- ContextMenu.Instance.addItem({
- description: "Minimize",
- event: this.minimize
- });
- }
- ContextMenu.Instance.addItem({
- description: "Full Screen",
- event: this.fullScreenClicked
- });
- ContextMenu.Instance.addItem({
- description: "Fields",
- event: this.fieldsClicked
- });
- ContextMenu.Instance.addItem({
- description: "Center",
- event: () => this.props.focus(this.props.Document)
- });
- ContextMenu.Instance.addItem({
- description: "Open Right",
- event: () =>
- CollectionDockingView.Instance.AddRightSplit(this.props.Document)
- });
- ContextMenu.Instance.addItem({
- description: "Copy URL",
- event: () => {
- Utils.CopyText(ServerUtils.prepend("/doc/" + this.props.Document.Id));
- }
- });
- ContextMenu.Instance.addItem({
- description: "Copy ID",
- event: () => {
- Utils.CopyText(this.props.Document.Id);
- }
- });
+ !this.isMinimized() && ContextMenu.Instance.addItem({ description: "Minimize", event: this.minimize });
+ ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked });
+ ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked });
+ ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) });
+ ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) });
+ ContextMenu.Instance.addItem({ description: "Copy URL", event: () => Utils.CopyText(ServerUtils.prepend("/doc/" + this.props.Document.Id)) });
+ ContextMenu.Instance.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document.Id) });
//ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) })
+ ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked });
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
- if (!this.topMost) {
- // DocumentViews should stop propagation of this event
- e.stopPropagation();
- }
-
- ContextMenu.Instance.addItem({
- description: "Delete",
- event: this.deleteClicked
- });
- ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
- SelectionManager.SelectDoc(this, e.ctrlKey);
- }
-
- isMinimized = () => {
- let field = this.props.Document.GetT(KeyStore.Minimized, BooleanField);
- if (field && field !== FieldWaiting) {
- return field.Data;
- }
+ if (!SelectionManager.IsSelected(this))
+ SelectionManager.SelectDoc(this, false);
}
@action
- expand = () => {
- this.props.Document.SetData(
- KeyStore.Minimized,
- false as boolean,
- BooleanField
- );
- }
-
+ expand = () => this.props.Document.SetBoolean(KeyStore.Minimized, false)
+ isMinimized = () => this.props.Document.GetBoolean(KeyStore.Minimized, false);
isSelected = () => SelectionManager.IsSelected(this);
+ select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed);
- select = (ctrlPressed: boolean) => {
- SelectionManager.SelectDoc(this, ctrlPressed);
- }
-
- @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 contents() {
- return (<DocumentContentsView
- {...this.props}
- isSelected={this.isSelected}
- select={this.select}
- layoutKey={KeyStore.Layout}
- />);
- }
+ @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() {
- if (!this.props.Document) {
- return null;
- }
-
var scaling = this.props.ContentScaling();
- var nativeWidth = this.nativeWidth;
- var nativeHeight = this.nativeHeight;
+ var nativeHeight = this.nativeHeight > 0 ? this.nativeHeight.toString() + "px" : "100%";
+ var nativeWidth = this.nativeWidth > 0 ? this.nativeWidth.toString() + "px" : "100%";
if (this.isMinimized()) {
- return (
- <div
- className="minimized-box"
- ref={this._mainCont}
- style={{
- transformOrigin: "left top",
- transform: `scale(${scaling} , ${scaling})`
- }}
- onClick={this.expand}
- onDrop={this.onDrop}
- onPointerDown={this.onPointerDown}
- />
- );
- } else {
- var backgroundcolor = this.props.Document.GetText(
- KeyStore.BackgroundColor,
- ""
- );
- return (
- <div
- className="documentView-node"
- ref={this._mainCont}
- style={{
- background: backgroundcolor,
- width: nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%",
- height: nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%",
- transformOrigin: "left top",
- transform: `scale(${scaling} , ${scaling})`
- }}
- onDrop={this.onDrop}
- onContextMenu={this.onContextMenu}
- onPointerDown={this.onPointerDown}
- >
- {this.contents}
- </div>
- );
+ return <div className="minimized-box" ref={this._mainCont} onClick={this.expand} onDrop={this.onDrop}
+ style={{ transform: `scale(${scaling} , ${scaling})` }} onPointerDown={this.onPointerDown} />;
}
+ return (
+ <div className={`documentView-node${this.props.isTopMost ? "-topmost" : ""}`}
+ ref={this._mainCont}
+ style={{
+ background: this.props.Document.GetText(KeyStore.BackgroundColor, ""),
+ width: nativeWidth, height: nativeHeight,
+ transform: `scale(${scaling}, ${scaling})`
+ }}
+ onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown}
+ >
+ {this.contents}
+ </div>
+ );
}
}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 0037d7b28..ebd25f937 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -1,7 +1,7 @@
import React = require("react");
import { observer } from "mobx-react";
import { computed } from "mobx";
-import { Field, FieldWaiting, FieldValue } from "../../../fields/Field";
+import { Field, FieldWaiting, FieldValue, Opt } from "../../../fields/Field";
import { Document } from "../../../fields/Document";
import { TextField } from "../../../fields/TextField";
import { NumberField } from "../../../fields/NumberField";
@@ -19,7 +19,10 @@ import { ListField } from "../../../fields/ListField";
import { DocumentContentsView } from "./DocumentContentsView";
import { Transform } from "../../util/Transform";
import { KeyStore } from "../../../fields/KeyStore";
-import { returnFalse, emptyDocFunction } from "../../../Utils";
+import { returnFalse, emptyDocFunction, emptyFunction, returnOne } from "../../../Utils";
+import { CollectionView } from "../collections/CollectionView";
+import { CollectionPDFView } from "../collections/CollectionPDFView";
+import { CollectionVideoView } from "../collections/CollectionVideoView";
//
@@ -29,6 +32,7 @@ import { returnFalse, emptyDocFunction } from "../../../Utils";
//
export interface FieldViewProps {
fieldKey: Key;
+ ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
Document: Document;
isSelected: () => boolean;
select: (isCtrlPressed: boolean) => void;
@@ -89,7 +93,7 @@ export class FieldView extends React.Component<FieldViewProps> {
isSelected={returnFalse}
select={returnFalse}
layoutKey={KeyStore.Layout}
- ContainingCollectionView={undefined}
+ ContainingCollectionView={this.props.ContainingCollectionView}
parentActive={this.props.active}
onActiveChanged={this.props.onActiveChanged} />
);
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 3978c3d38..5eb2bf7ce 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -10,7 +10,7 @@
outline: none !important;
}
-.formattedTextBox-cont {
+.formattedTextBox-cont-scroll, .formattedTextBox-cont-hidden {
background: $light-color-secondary;
padding: 0.9em;
border-width: 0px;
@@ -24,6 +24,10 @@
height: 100%;
pointer-events: all;
}
+.formattedTextBox-cont-hidden {
+ overflow: hidden;
+ pointer-events: none;
+}
.menuicon {
display: inline-block;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index a49497f8f..bff8ca7a4 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,21 +1,24 @@
import { action, IReactionDisposer, reaction } from "mobx";
import { baseKeymap } from "prosemirror-commands";
-import { history, redo, undo } from "prosemirror-history";
+import { history } from "prosemirror-history";
import { keymap } from "prosemirror-keymap";
import { EditorState, Plugin, Transaction } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { FieldWaiting, Opt } from "../../../fields/Field";
+import { KeyStore } from "../../../fields/KeyStore";
import { RichTextField } from "../../../fields/RichTextField";
+import { TextField } from "../../../fields/TextField";
+import { Document } from "../../../fields/Document";
+import buildKeymap from "../../util/ProsemirrorKeymap";
import { inpRules } from "../../util/RichTextRules";
import { schema } from "../../util/RichTextSchema";
+import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu";
import { TooltipTextMenu } from "../../util/TooltipTextMenu";
import { ContextMenu } from "../../views/ContextMenu";
-import { Main } from "../Main";
+import { MainOverlayTextBox } from "../MainOverlayTextBox";
import { FieldView, FieldViewProps } from "./FieldView";
import "./FormattedTextBox.scss";
import React = require("react");
-import { TextField } from "../../../fields/TextField";
-import { KeyStore } from "../../../fields/KeyStore";
const { buildMenuItems } = require("prosemirror-example-setup");
const { menuBar } = require("prosemirror-menu");
@@ -46,6 +49,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
}
private _ref: React.RefObject<HTMLDivElement>;
private _editorView: Opt<EditorView>;
+ private _gotDown: boolean = false;
private _reactionDisposer: Opt<IReactionDisposer>;
private _inputReactionDisposer: Opt<IReactionDisposer>;
private _proxyReactionDisposer: Opt<IReactionDisposer>;
@@ -81,29 +85,34 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
inpRules, //these currently don't do anything, but could eventually be helpful
plugins: this.props.isOverlay ? [
history(),
- keymap({ "Mod-z": undo, "Mod-y": redo }),
+ keymap(buildKeymap(schema)),
keymap(baseKeymap),
- this.tooltipMenuPlugin()
+ this.tooltipTextMenuPlugin(),
+ // this.tooltipLinkingMenuPlugin(),
+ new Plugin({
+ props: {
+ attributes: { class: "ProseMirror-example-setup-style" }
+ }
+ })
] : [
history(),
- keymap({ "Mod-z": undo, "Mod-y": redo }),
+ keymap(buildKeymap(schema)),
keymap(baseKeymap),
]
};
if (this.props.isOverlay) {
- this._inputReactionDisposer = reaction(() => Main.Instance._textDoc && Main.Instance._textDoc.Id,
+ this._inputReactionDisposer = reaction(() => MainOverlayTextBox.Instance.TextDoc && MainOverlayTextBox.Instance.TextDoc.Id,
() => {
if (this._editorView) {
this._editorView.destroy();
}
-
- this.setupEditor(config);
+ this.setupEditor(config, MainOverlayTextBox.Instance.TextDoc); // bcz: not sure why, but the order of events is such that this.props.Document hasn't updated yet, so without forcing the editor to the MainOverlayTextBox, it will display the previously focused textbox
}
);
} else {
this._proxyReactionDisposer = reaction(() => this.props.isSelected(),
- () => this.props.isSelected() && Main.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform()));
+ () => this.props.isSelected() && MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform()));
}
this._reactionDisposer = reaction(
@@ -119,20 +128,18 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
}
}
);
- this.setupEditor(config);
+ this.setupEditor(config, this.props.Document);
}
- private setupEditor(config: any) {
- let state: EditorState;
- let field = this.props.Document ? this.props.Document.GetT(this.props.fieldKey, RichTextField) : undefined;
- if (field && field !== FieldWaiting && field.Data) {
- state = EditorState.fromJSON(config, JSON.parse(field.Data));
- } else {
- state = EditorState.create(config);
- }
+ shouldComponentUpdate() {
+ return false;
+ }
+
+ private setupEditor(config: any, doc?: Document) {
+ let field = doc ? doc.GetT(this.props.fieldKey, RichTextField) : undefined;
if (this._ref.current) {
this._editorView = new EditorView(this._ref.current, {
- state,
+ state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config),
dispatchTransaction: this.dispatchTransaction
});
}
@@ -158,10 +165,6 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
}
}
- shouldComponentUpdate() {
- return false;
- }
-
@action
onChange(e: React.ChangeEvent<HTMLInputElement>) {
const { fieldKey, Document } = this.props;
@@ -170,13 +173,17 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
}
onPointerDown = (e: React.PointerEvent): void => {
if (e.button === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
+ console.log("first");
e.stopPropagation();
}
if (e.button === 2) {
+ this._gotDown = true;
+ console.log("second");
e.preventDefault();
}
}
onPointerUp = (e: React.PointerEvent): void => {
+ console.log("pointer up");
if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
e.stopPropagation();
}
@@ -184,10 +191,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
onFocused = (e: React.FocusEvent): void => {
if (!this.props.isOverlay) {
- Main.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform());
+ MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform());
} else {
if (this._ref.current) {
- this._ref.current.scrollTop = Main.Instance._textScroll;
+ this._ref.current.scrollTop = MainOverlayTextBox.Instance.TextScroll;
}
}
}
@@ -196,6 +203,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
textCapability = (e: React.MouseEvent): void => { };
specificContextMenu = (e: React.MouseEvent): void => {
+ if (!this._gotDown) {
+ e.preventDefault();
+ return;
+ }
ContextMenu.Instance.addItem({
description: "Text Capability",
event: this.textCapability
@@ -216,10 +227,12 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
}
onPointerWheel = (e: React.WheelEvent): void => {
- e.stopPropagation();
+ if (this.props.isSelected()) {
+ e.stopPropagation();
+ }
}
- tooltipMenuPlugin() {
+ tooltipTextMenuPlugin() {
let myprops = this.props;
return new Plugin({
view(_editorView) {
@@ -227,16 +240,27 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
}
});
}
+
+ tooltipLinkingMenuPlugin() {
+ let myprops = this.props;
+ return new Plugin({
+ view(_editorView) {
+ return new TooltipLinkingMenu(_editorView, myprops);
+ }
+ });
+ }
+
onKeyPress(e: React.KeyboardEvent) {
e.stopPropagation();
+ if (e.keyCode === 9) 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;
}
render() {
+ let style = this.props.isSelected() || this.props.isOverlay ? "scroll" : "hidden";
return (
- <div
- className={`formattedTextBox-cont`}
+ <div className={`formattedTextBox-cont-${style}`}
onKeyDown={this.onKeyPress}
onKeyPress={this.onKeyPress}
onFocus={this.onFocused}
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 487038841..f4b3837ff 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -8,6 +8,16 @@
max-height: 100%;
}
+.imageBox-dot {
+ position:absolute;
+ bottom: 10;
+ left: 0;
+ border-radius: 10px;
+ width:20px;
+ height:20px;
+ background:gray;
+}
+
.imageBox-cont img {
height: 100%;
width:100%;
@@ -18,4 +28,4 @@
border: none;
width: 100%;
height: 100%;
-}
+} \ No newline at end of file
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 6b0a3a799..71b431b84 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,51 +1,84 @@
-import { action, observable, trace } from 'mobx';
+import { action, observable } from 'mobx';
import { observer } from "mobx-react";
import Lightbox from 'react-image-lightbox';
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
+import { Document } from '../../../fields/Document';
import { FieldWaiting } from '../../../fields/Field';
import { ImageField } from '../../../fields/ImageField';
import { KeyStore } from '../../../fields/KeyStore';
+import { ListField } from '../../../fields/ListField';
+import { Utils } from '../../../Utils';
+import { DragManager } from '../../util/DragManager';
+import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from "../../views/ContextMenu";
import { FieldView, FieldViewProps } from './FieldView';
import "./ImageBox.scss";
import React = require("react");
-import { Utils } from '../../../Utils';
@observer
export class ImageBox extends React.Component<FieldViewProps> {
public static LayoutString() { return FieldView.LayoutString(ImageBox); }
- private _ref: React.RefObject<HTMLDivElement>;
private _imgRef: React.RefObject<HTMLImageElement>;
private _downX: number = 0;
private _downY: number = 0;
private _lastTap: number = 0;
@observable private _photoIndex: number = 0;
@observable private _isOpen: boolean = false;
+ private dropDisposer?: DragManager.DragDropDisposer;
constructor(props: FieldViewProps) {
super(props);
- this._ref = React.createRef();
this._imgRef = React.createRef();
- this.state = {
- photoIndex: 0,
- isOpen: false,
- };
}
@action
onLoad = (target: any) => {
var h = this._imgRef.current!.naturalHeight;
var w = this._imgRef.current!.naturalWidth;
- this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w);
+ if (this._photoIndex === 0) this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w);
}
- componentDidMount() {
+
+ protected createDropTarget = (ele: HTMLDivElement) => {
+ if (this.dropDisposer) {
+ this.dropDisposer();
+ }
+ if (ele) {
+ this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
+ }
+ }
+ onDrop = (e: React.DragEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ console.log("IMPLEMENT ME PLEASE");
}
- componentWillUnmount() {
+
+ @undoBatch
+ drop = (e: Event, de: DragManager.DropEvent) => {
+ if (de.data instanceof DragManager.DocumentDragData) {
+ de.data.droppedDocuments.map(action((drop: Document) => {
+ let layout = drop.GetText(KeyStore.BackgroundLayout, "");
+ if (layout.indexOf(ImageBox.name) !== -1) {
+ let imgData = this.props.Document.Get(KeyStore.Data);
+ if (imgData instanceof ImageField && imgData) {
+ this.props.Document.Set(KeyStore.Data, new ListField([imgData]));
+ }
+ let imgList = this.props.Document.GetList(KeyStore.Data, [] as any[]);
+ if (imgList) {
+ let field = drop.Get(KeyStore.Data);
+ if (field === FieldWaiting) { }
+ else if (field instanceof ImageField) imgList.push(field);
+ else if (field instanceof ListField) imgList.push(field.Data);
+ }
+ e.stopPropagation();
+ }
+ }));
+ // de.data.removeDocument() bcz: need to implement
+ }
}
onPointerDown = (e: React.PointerEvent): void => {
@@ -70,8 +103,7 @@ export class ImageBox extends React.Component<FieldViewProps> {
e.stopPropagation();
}
- lightbox = (path: string) => {
- const images = [path];
+ lightbox = (images: string[]) => {
if (this._isOpen) {
return (<Lightbox
mainSrc={images[this._photoIndex]}
@@ -102,15 +134,34 @@ export class ImageBox extends React.Component<FieldViewProps> {
}
}
+ @action
+ onDotDown(index: number) {
+ this._photoIndex = index;
+ }
+
+ dots(paths: string[]) {
+ let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1);
+ let dist = Math.min(nativeWidth / paths.length, 40);
+ let left = (nativeWidth - paths.length * dist) / 2;
+ return paths.map((p, i) =>
+ <div className="imageBox-placer" key={i} >
+ <div className="imageBox-dot" style={{ background: (i === this._photoIndex ? "black" : "gray"), transform: `translate(${i * dist + left}px, 0px)` }} onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); this.onDotDown(i); }} />
+ </div>
+ );
+ }
+
render() {
let field = this.props.Document.Get(this.props.fieldKey);
- let path = field === FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
- field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif";
+ let paths: string[] = ["http://www.cs.brown.edu/~bcz/face.gif"];
+ if (field === FieldWaiting) paths = ["https://image.flaticon.com/icons/svg/66/66163.svg"];
+ 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);
return (
- <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} onContextMenu={this.specificContextMenu}>
- <img src={path} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} />
- {this.lightbox(path)}
+ <div className="imageBox-cont" 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)}
</div>);
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 29e4af160..ddbec014b 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -26,12 +26,6 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
super(props);
}
-
-
- shouldComponentUpdate() {
- return false;
- }
-
@action
onEnterKey = (e: React.KeyboardEvent): void => {
if (e.key === 'Enter') {
diff --git a/src/client/views/nodes/KeyValuePair.scss b/src/client/views/nodes/KeyValuePair.scss
index 04d002c7b..01701e02c 100644
--- a/src/client/views/nodes/KeyValuePair.scss
+++ b/src/client/views/nodes/KeyValuePair.scss
@@ -1,30 +1,28 @@
@import "../globalCssVariables";
-.container{
- width:100%;
- height:100%;
- display: flex;
- flex-direction: row;
- flex-wrap: nowrap;
- justify-content: space-between;
-}
.keyValuePair-td-key {
display:inline-block;
- width: 50%;
+ .keyValuePair-td-key-container{
+ width:100%;
+ height:100%;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+ .keyValuePair-td-key-delete{
+ position: relative;
+ background-color: transparent;
+ color:red;
+ }
+ .keyValuePair-keyField {
+ width:100%;
+ text-align: center;
+ position: relative;
+ overflow: auto;
+ }
+ }
}
.keyValuePair-td-value {
display:inline-block;
- width: 50%;
-}
-.keyValuePair-keyField {
- width:100%;
- text-align: center;
- position: relative;
- overflow: auto;
-}
-.delete{
- position: relative;
- background-color: transparent;
- color:red;
} \ No newline at end of file
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 3e0b61c3d..5d69f23b2 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -1,18 +1,18 @@
-import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
-import "./KeyValueBox.scss";
-import "./KeyValuePair.scss";
-import React = require("react");
-import { FieldViewProps, FieldView } from './FieldView';
-import { Opt, Field } from '../../../fields/Field';
+import { action, observable } from 'mobx';
import { observer } from "mobx-react";
-import { observable, action } from 'mobx';
+import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
import { Document } from '../../../fields/Document';
+import { Field, Opt } from '../../../fields/Field';
import { Key } from '../../../fields/Key';
+import { emptyDocFunction, emptyFunction, returnFalse } from '../../../Utils';
import { Server } from "../../Server";
-import { EditableView } from "../EditableView";
import { CompileScript, ToField } from "../../util/Scripting";
import { Transform } from '../../util/Transform';
-import { returnFalse, emptyFunction, emptyDocFunction } from '../../../Utils';
+import { EditableView } from "../EditableView";
+import { FieldView, FieldViewProps } from './FieldView';
+import "./KeyValueBox.scss";
+import "./KeyValuePair.scss";
+import React = require("react");
// Represents one row in a key value plane
@@ -25,28 +25,23 @@ export interface KeyValuePairProps {
@observer
export class KeyValuePair extends React.Component<KeyValuePairProps> {
- @observable
- private key: Opt<Key>;
+ @observable private key: Opt<Key>;
constructor(props: KeyValuePairProps) {
super(props);
Server.GetField(this.props.fieldId,
- action((field: Opt<Field>) => {
- if (field) {
- this.key = field as Key;
- }
- }));
+ action((field: Opt<Field>) => field instanceof Key && (this.key = field)));
}
render() {
if (!this.key) {
- return <tr><td>error</td><td></td></tr>;
-
+ return <tr><td>error</td><td /></tr>;
}
let props: FieldViewProps = {
Document: this.props.doc,
+ ContainingCollectionView: undefined,
fieldKey: this.key,
isSelected: returnFalse,
select: emptyFunction,
@@ -57,19 +52,17 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
ScreenToLocalTransform: Transform.Identity,
focus: emptyDocFunction,
};
- let contents = (
- <FieldView {...props} />
- );
+ let contents = <FieldView {...props} />;
return (
<tr className={this.props.rowStyle}>
<td className="keyValuePair-td-key" style={{ width: `${this.props.keyWidth}%` }}>
- <div className="container">
- <button className="delete" onClick={() => {
+ <div className="keyValuePair-td-key-container">
+ <button className="keyValuePair-td-key-delete" onClick={() => {
let field = props.Document.Get(props.fieldKey);
- if (field && field instanceof Field) {
- props.Document.Set(props.fieldKey, undefined);
- }
- }}>X</button>
+ field && field instanceof Field && props.Document.Set(props.fieldKey, undefined);
+ }}>
+ X
+ </button>
<div className="keyValuePair-keyField">{this.key.Name}</div>
</div>
</td>
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index c73bc0c47..2ad1129a4 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -9,6 +9,12 @@
overflow: scroll;
}
+#webBox-htmlSpan {
+ position: absolute;
+ top:0;
+ left:0;
+}
+
.webBox-button {
padding : 0vw;
border: none;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 90ce72c41..1edb4d826 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -18,21 +18,40 @@ export class WebBox extends React.Component<FieldViewProps> {
@computed get html(): string { return this.props.Document.GetHtml(KeyStore.Data, ""); }
+ _ignore = 0;
+ onPreWheel = (e: React.WheelEvent) => {
+ this._ignore = e.timeStamp;
+ }
+ onPrePointer = (e: React.PointerEvent) => {
+ this._ignore = e.timeStamp;
+ }
+ onPostPointer = (e: React.PointerEvent) => {
+ if (this._ignore !== e.timeStamp) {
+ e.stopPropagation();
+ }
+ }
+ onPostWheel = (e: React.WheelEvent) => {
+ if (this._ignore !== e.timeStamp) {
+ e.stopPropagation();
+ }
+ }
render() {
let field = this.props.Document.Get(this.props.fieldKey);
let path = field === FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
field instanceof WebField ? field.Data.href : "https://crossorigin.me/" + "https://cs.brown.edu";
- let content = this.html ?
- <span dangerouslySetInnerHTML={{ __html: this.html }}></span> :
- <div style={{ width: "100%", height: "100%", position: "absolute" }}>
- <iframe src={path} style={{ position: "absolute", width: "100%", height: "100%" }}></iframe>
- {this.props.isSelected() ? (null) : <div style={{ width: "100%", height: "100%", position: "absolute" }} />}
+ let content =
+ <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
+ {this.html ? <span id="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: this.html }} /> :
+ <iframe src={path} style={{ position: "absolute", width: "100%", height: "100%" }} />}
</div>;
return (
- <div className="webBox-cont" >
- {content}
- </div>);
+ <>
+ <div className="webBox-cont" >
+ {content}
+ </div>
+ {this.props.isSelected() ? (null) : <div onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer} style={{ width: "100%", height: "100%", position: "absolute" }} />}
+ </>);
}
} \ No newline at end of file