From f9d241406c62b6aba1a84b5947d339c1a4c28a6d Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 30 Jan 2019 13:36:03 -0500 Subject: fixed dragging and doc decorations for all docking locations I think. --- src/DocumentDecorations.scss | 2 +- src/Main.tsx | 7 +-- src/views/collections/CollectionDockingView.tsx | 52 ++++++---------- src/views/collections/CollectionFreeFormView.tsx | 19 +++--- src/views/nodes/DocumentView.tsx | 78 +++++++++++++----------- src/views/nodes/FieldTextBox.tsx | 37 ++++++----- 6 files changed, 98 insertions(+), 97 deletions(-) (limited to 'src') diff --git a/src/DocumentDecorations.scss b/src/DocumentDecorations.scss index 2840d782b..252b0f53f 100644 --- a/src/DocumentDecorations.scss +++ b/src/DocumentDecorations.scss @@ -10,7 +10,7 @@ .documentDecorations-resizer { pointer-events: auto; background: lightblue; - opacity: 0.8; + opacity: 0.4; } #documentDecorations-topLeftResizer, #documentDecorations-bottomRightResizer { diff --git a/src/Main.tsx b/src/Main.tsx index 02b866753..73fc06941 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -56,7 +56,7 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { x: 650, y: 500, width: 600, height: 600, title: "cat" }); let docset2 = new Array(doc4, doc1, doc3); - let doc6 = Documents.DockDocument(docset2, { + let doc6 = Documents.CollectionDocument(docset2, { x: 350, y: 100, width: 600, height: 600, title: "docking collection" }); let mainNodes = null;// mainContainer.GetFieldT(KeyStore.Data, ListField); @@ -69,15 +69,14 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { // mainNodes.Data.push(doc3); mainNodes.Data.push(doc5); // mainNodes.Data.push(doc1); - mainNodes.Data.push(doc2); - //mainNodes.Data.push(doc6); + //mainNodes.Data.push(doc2); + mainNodes.Data.push(doc6); mainContainer.SetField(KeyStore.Data, mainNodes); } //); ReactDOM.render((
-

Dash Web

diff --git a/src/views/collections/CollectionDockingView.tsx b/src/views/collections/CollectionDockingView.tsx index fd492503d..f08bdaab4 100644 --- a/src/views/collections/CollectionDockingView.tsx +++ b/src/views/collections/CollectionDockingView.tsx @@ -4,7 +4,7 @@ import React = require("react"); import FlexLayout from "flexlayout-react"; import { action, observable, computed } from "mobx"; import { Document } from "../../fields/Document"; -import { DocumentView, CollectionViewProps } from "../nodes/DocumentView"; +import { DocumentView, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "../nodes/DocumentView"; import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; import { SSL_OP_SINGLE_DH_USE } from "constants"; @@ -52,9 +52,6 @@ export class CollectionDockingView extends React.Component super(props); } - public static BORDER_WIDTH = 2; - public static TAB_HEADER_HEIGHT = 20; - @computed public get active(): boolean { var isSelected = (this.props.ContainingDocumentView != undefined && SelectionManager.IsSelected(this.props.ContainingDocumentView)); @@ -169,35 +166,24 @@ export class CollectionDockingView extends React.Component var w = Document.GetFieldValue(KeyStore.Width, NumberField, Number(0)) / s; var h = Document.GetFieldValue(KeyStore.Height, NumberField, Number(0)) / s; - if (CollectionDockingView.UseGoldenLayout) { - return ( -
-
e.preventDefault()} ref={this._containerRef} - style={{ - width: "100%", - height: "100%" - }} > -
-
- ); - } else { - return ( -
-
e.preventDefault()} ref={this._containerRef} - style={{ - width: s > 1 ? "100%" : w - 2 * CollectionDockingView.BORDER_WIDTH, - height: s > 1 ? "100%" : h - 2 * CollectionDockingView.BORDER_WIDTH - }} > - -
-
- ); + var chooseLayout = () => { + if (!CollectionDockingView.UseGoldenLayout) + return ; } + + return ( +
+
e.preventDefault()} ref={this._containerRef} + style={{ + width: CollectionDockingView.UseGoldenLayout || s > 1 ? "100%" : w - 2 * COLLECTION_BORDER_WIDTH, + height: CollectionDockingView.UseGoldenLayout || s > 1 ? "100%" : h - 2 * COLLECTION_BORDER_WIDTH + }} > + {chooseLayout()} +
+
+ ); } } \ No newline at end of file diff --git a/src/views/collections/CollectionFreeFormView.tsx b/src/views/collections/CollectionFreeFormView.tsx index 736bcb786..58e694698 100644 --- a/src/views/collections/CollectionFreeFormView.tsx +++ b/src/views/collections/CollectionFreeFormView.tsx @@ -3,7 +3,7 @@ import { Key, KeyStore } from "../../fields/Key"; import React = require("react"); import { action, observable, computed } from "mobx"; import { Document } from "../../fields/Document"; -import { DocumentView, CollectionViewProps } from "../nodes/DocumentView"; +import { DocumentView, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "../nodes/DocumentView"; import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; import { SSL_OP_SINGLE_DH_USE } from "constants"; @@ -24,8 +24,6 @@ export class CollectionFreeFormView extends React.Component super(props); } - public static BORDER_WIDTH = 2; - @computed public get active(): boolean { var isSelected = (this.props.ContainingDocumentView != undefined && SelectionManager.IsSelected(this.props.ContainingDocumentView)); @@ -45,9 +43,14 @@ export class CollectionFreeFormView extends React.Component } const xOffset = de.data[ "xOffset" ] as number || 0; const yOffset = de.data[ "yOffset" ] as number || 0; - let { LocalX, LocalY } = this.props.ContainingDocumentView!.TransformToLocalPoint(de.x - xOffset, de.y - yOffset); - doc.x = LocalX; - doc.y = LocalY; + const { scale, translateX, translateY } = Utils.GetScreenTransform(this._canvasRef.current!); + let sscale = this.props.ContainingDocumentView!.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)) + const screenX = de.x - xOffset; + const screenY = de.y - yOffset; + const docX = (screenX - translateX) / sscale / scale; + const docY = (screenY - translateY) / sscale / scale; + doc.x = docX; + doc.y = docY; } e.stopPropagation(); } @@ -181,11 +184,11 @@ export class CollectionFreeFormView extends React.Component return (
e.preventDefault()} style={{ width: "100%", - height: `calc(100% - 2*${CollectionFreeFormView.BORDER_WIDTH}px)`, + height: `calc(100% - 2*${COLLECTION_BORDER_WIDTH}px)`, }} onDrop={this.onDrop} onDragOver={this.onDragOver} ref={this._containerRef}>
diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx index 1e4cc1cca..3c4dfa36f 100644 --- a/src/views/nodes/DocumentView.tsx +++ b/src/views/nodes/DocumentView.tsx @@ -1,19 +1,20 @@ +import { action, computed } from "mobx"; import { observer } from "mobx-react"; -import React = require("react"); -import { computed, observable, action } from "mobx"; -import { KeyStore, Key } from "../../fields/Key"; +import { Document } from "../../fields/Document"; +import { Opt } from "../../fields/Field"; +import { Key, KeyStore } from "../../fields/Key"; +import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; import { TextField } from "../../fields/TextField"; -import { ListField } from "../../fields/ListField"; -import { FieldTextBox } from "../nodes/FieldTextBox" -import { Document } from "../../fields/Document"; -import { CollectionFreeFormView } from "../collections/CollectionFreeFormView" -import { CollectionDockingView } from "../collections/CollectionDockingView" -import "./NodeView.scss" +import { DragManager } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; +import { Utils } from "../../Utils"; +import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { CollectionFreeFormView } from "../collections/CollectionFreeFormView"; import { ContextMenu } from "../ContextMenu"; -import { Opt } from "../../fields/Field"; -import { DragManager } from "../../util/DragManager"; +import { FieldTextBox } from "../nodes/FieldTextBox"; +import "./NodeView.scss"; +import React = require("react"); const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? interface DocumentViewProps { @@ -28,13 +29,7 @@ export interface CollectionViewProps { ContainingDocumentView: Opt; } -// these properties are set via the render() method of the DocumentView when it creates this node. -// However, these properties are set below in the LayoutString() static method -export interface DocumentFieldViewProps { - fieldKey: Key; - doc: Document; - containingDocumentView: DocumentView -} +export const COLLECTION_BORDER_WIDTH = 2; interface CollectionView { addDocument: (doc: Document) => void; @@ -169,20 +164,25 @@ export class DocumentView extends React.Component { // Converts a coordinate in the screen space of the app into a local document coordinate. // public TransformToLocalPoint(screenX: number, screenY: number) { - let ContainerX = screenX - CollectionFreeFormView.BORDER_WIDTH; - let ContainerY = screenY - CollectionFreeFormView.BORDER_WIDTH; - // if this collection view is nested within another collection view, then // first transform the screen point into the parent collection's coordinate space. - if (this.props.ContainingDocumentView != undefined) { - let { LocalX, LocalY } = this.props.ContainingDocumentView!.TransformToLocalPoint(screenX, screenY); - ContainerX = LocalX - CollectionFreeFormView.BORDER_WIDTH; - ContainerY = LocalY - CollectionFreeFormView.BORDER_WIDTH; + let { LocalX: parentX, LocalY: parentY } = this.props.ContainingDocumentView != undefined ? + this.props.ContainingDocumentView!.TransformToLocalPoint(screenX, screenY) : + { LocalX: screenX, LocalY: screenY }; + let ContainerX: number = parentX - COLLECTION_BORDER_WIDTH; + let ContainerY: number = parentY - COLLECTION_BORDER_WIDTH; + + var Xx = this.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0)); + var Yy = this.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0)); + // CollectionDockingViews change the location of their children frames without using a Dash transformation. + // They also ignore any transformation that may have been applied to their content document. + // NOTE: this currently assumes CollectionDockingViews aren't nested. + if (this.props.ContainingCollectionView instanceof CollectionDockingView) { + var { translateX: rx, translateY: ry } = Utils.GetScreenTransform(this._mainCont.current!); + Xx = rx - COLLECTION_BORDER_WIDTH; + Yy = ry - COLLECTION_BORDER_WIDTH; } - let dockingViewChromeHack = this.props.ContainingCollectionView instanceof CollectionDockingView; - let Xx = dockingViewChromeHack ? 0 : this.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0)); - let Yy = dockingViewChromeHack ? CollectionDockingView.TAB_HEADER_HEIGHT : this.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0)); let Ss = this.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)); let Panxx = this.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); let Panyy = this.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); @@ -197,11 +197,19 @@ export class DocumentView extends React.Component { // public TransformToScreenPoint(localX: number, localY: number, Ss: number = 1, Panxx: number = 0, Panyy: number = 0): { ScreenX: number, ScreenY: number } { - let dockingViewChromeHack = this.props.ContainingCollectionView instanceof CollectionDockingView; - let W = CollectionFreeFormView.BORDER_WIDTH; // this.props.Document.GetFieldValue(KeyStore.Width, NumberField, Number(0)); - let H = CollectionFreeFormView.BORDER_WIDTH; - let Xx = dockingViewChromeHack ? 0 : this.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0)); - let Yy = dockingViewChromeHack ? CollectionDockingView.TAB_HEADER_HEIGHT : this.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0)); + var Xx = this.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0)); + var Yy = this.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0)); + // CollectionDockingViews change the location of their children frames without using a Dash transformation. + // They also ignore any transformation that may have been applied to their content document. + // NOTE: this currently assumes CollectionDockingViews aren't nested. + if (this.props.ContainingCollectionView instanceof CollectionDockingView) { + var { translateX: rx, translateY: ry } = Utils.GetScreenTransform(this._mainCont.current!); + Xx = rx - COLLECTION_BORDER_WIDTH; + Yy = ry - COLLECTION_BORDER_WIDTH; + } + + let W = COLLECTION_BORDER_WIDTH; + let H = COLLECTION_BORDER_WIDTH; let parentX = (localX - W) * Ss + (Xx + Panxx) + W; let parentY = (localY - H) * Ss + (Yy + Panyy) + H; @@ -210,8 +218,8 @@ export class DocumentView extends React.Component { let containingDocView = this.props.ContainingDocumentView; if (containingDocView != undefined) { let ss = containingDocView.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)); - let panxx = containingDocView.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)) + CollectionFreeFormView.BORDER_WIDTH * ss; - let panyy = containingDocView.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)) + CollectionFreeFormView.BORDER_WIDTH * ss; + let panxx = containingDocView.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)) + COLLECTION_BORDER_WIDTH * ss; + let panyy = containingDocView.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)) + COLLECTION_BORDER_WIDTH * ss; let { ScreenX, ScreenY } = containingDocView.TransformToScreenPoint(parentX, parentY, ss, panxx, panyy); parentX = ScreenX; parentY = ScreenY; diff --git a/src/views/nodes/FieldTextBox.tsx b/src/views/nodes/FieldTextBox.tsx index 20dfde1d2..45493f0ec 100644 --- a/src/views/nodes/FieldTextBox.tsx +++ b/src/views/nodes/FieldTextBox.tsx @@ -1,23 +1,28 @@ -import { Key, KeyStore } from "../../fields/Key"; -import { Document } from "../../fields/Document"; -import { observer } from "mobx-react"; -import { TextField } from "../../fields/TextField"; -import React = require("react") -import { action, observable, reaction, IReactionDisposer } from "mobx"; - +import { action, IReactionDisposer, reaction } from "mobx"; +import { baseKeymap } from "prosemirror-commands"; +import { history, redo, undo } from "prosemirror-history"; +import { keymap } from "prosemirror-keymap"; import { schema } from "prosemirror-schema-basic"; -import { EditorState, Transaction } from "prosemirror-state" -import { EditorView } from "prosemirror-view" -import { keymap } from "prosemirror-keymap" -import { baseKeymap } from "prosemirror-commands" -import { undo, redo, history } from "prosemirror-history" +import { EditorState, Transaction } from "prosemirror-state"; +import { EditorView } from "prosemirror-view"; +import { Document } from "../../fields/Document"; import { Opt } from "../../fields/Field"; - -import "./FieldTextBox.scss" -import { DocumentFieldViewProps } from "./DocumentView"; +import { Key } from "../../fields/Key"; +import { TextField } from "../../fields/TextField"; import { SelectionManager } from "../../util/SelectionManager"; +import { DocumentView } from "./DocumentView"; +import "./FieldTextBox.scss"; +import React = require("react") - +// +// these properties get assigned through the render() method of the DocumentView when it creates this node. +// However, that only happens because the properties are "defined" in FieldTextBox's LayoutString() method +// +interface DocumentFieldViewProps { + fieldKey: Key; + doc: Document; + containingDocumentView: DocumentView +} // FieldTextBox: Displays an editable plain text node that maps to a specified Key of a Document // -- cgit v1.2.3-70-g09d2 From 0493f7f18a3eb49d0443f1742d53bb214bf9dd70 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 30 Jan 2019 17:36:30 -0500 Subject: drag drop fixes for docking --- package-lock.json | 144 ++++++++++++++++++----- package.json | 3 +- src/Main.tsx | 4 +- src/util/DragManager.ts | 2 + src/views/collections/CollectionDockingView.scss | 25 ++-- src/views/collections/CollectionDockingView.tsx | 58 +++++++-- src/views/collections/CollectionFreeFormView.tsx | 1 + src/views/nodes/DocumentView.tsx | 7 ++ webpack.config.js | 11 ++ 9 files changed, 202 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/package-lock.json b/package-lock.json index 192a10f9e..de2300c03 100644 --- a/package-lock.json +++ b/package-lock.json @@ -392,14 +392,12 @@ "ajv-errors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" }, "ajv-keywords": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", - "dev": true + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "amdefine": { "version": "1.0.1", @@ -711,8 +709,7 @@ "big.js": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "dev": true + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" }, "binary-extensions": { "version": "1.12.0", @@ -1540,23 +1537,55 @@ } }, "css-loader": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.0.1.tgz", - "integrity": "sha512-XIVwoIOzSFRVsafOKa060GJ/A70c0IP/C1oVPHEX4eHIFF39z0Jl7j8Kua1SUTiqWDupUnbY3/yQx9r7EUB35w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.0.tgz", + "integrity": "sha512-MoOu+CStsGrSt5K2OeZ89q3Snf+IkxRfAIt9aAKg4piioTrhtP1iEFPu+OVn3Ohz24FO6L+rw9UJxBILiSBw5Q==", "dev": true, "requires": { "icss-utils": "4.0.0", - "loader-utils": "1.1.0", + "loader-utils": "1.2.3", "lodash": "4.17.11", - "postcss": "7.0.7", + "postcss": "7.0.14", "postcss-modules-extract-imports": "2.0.0", - "postcss-modules-local-by-default": "2.0.2", + "postcss-modules-local-by-default": "2.0.4", "postcss-modules-scope": "2.0.1", "postcss-modules-values": "2.0.0", "postcss-value-parser": "3.3.1", "schema-utils": "1.0.0" }, "dependencies": { + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "1.2.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "5.2.2", + "emojis-list": "2.1.0", + "json5": "1.0.1" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -1895,8 +1924,7 @@ "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" }, "encodeurl": { "version": "1.0.2", @@ -3384,7 +3412,7 @@ "integrity": "sha512-bA/xGiwWM17qjllIs9X/y0EjsB7e0AV08F3OL8UPsoNkNRibIuu8f1eKTnQ8QO1DteKKTxTUAn+IEWUToIwGOA==", "dev": true, "requires": { - "postcss": "7.0.7" + "postcss": "7.0.14" } }, "ieee754": { @@ -3773,8 +3801,7 @@ "json5": { "version": "0.5.1", "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsprim": { "version": "1.4.1", @@ -3837,7 +3864,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "dev": true, "requires": { "big.js": "3.2.0", "emojis-list": "2.1.0", @@ -7981,21 +8007,52 @@ "dev": true }, "postcss": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.7.tgz", - "integrity": "sha512-HThWSJEPkupqew2fnuQMEI2YcTj/8gMV3n80cMdJsKxfIh5tHf7nM5JigNX6LxVMqo6zkgQNAI88hyFvBk41Pg==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", + "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", "dev": true, "requires": { - "chalk": "2.4.1", + "chalk": "2.4.2", "source-map": "0.6.1", - "supports-color": "5.5.0" + "supports-color": "6.1.0" }, "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } } } }, @@ -8005,17 +8062,17 @@ "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", "dev": true, "requires": { - "postcss": "7.0.7" + "postcss": "7.0.14" } }, "postcss-modules-local-by-default": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.2.tgz", - "integrity": "sha512-qghHvHeydUBQ3EQic5NjYryZ5jzXzAYxHR7lZQlCNmjGpJtINRyX/ELnh/7fxBBmHNkEzNkq2l5cV6trfidYng==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.4.tgz", + "integrity": "sha512-WvuSaTKXUqYJbnT7R3YrsNrHv/C5vRfr5VglS4bFOk0MYT4CLBfc/xgExA+x2RftlYgiBDvWmVs191Xv8S8gZQ==", "dev": true, "requires": { "css-selector-tokenizer": "0.7.1", - "postcss": "7.0.7", + "postcss": "7.0.14", "postcss-value-parser": "3.3.1" } }, @@ -8026,7 +8083,7 @@ "dev": true, "requires": { "css-selector-tokenizer": "0.7.1", - "postcss": "7.0.7" + "postcss": "7.0.14" } }, "postcss-modules-values": { @@ -8036,7 +8093,7 @@ "dev": true, "requires": { "icss-replace-symbols": "1.1.0", - "postcss": "7.0.7" + "postcss": "7.0.14" } }, "postcss-value-parser": { @@ -9849,6 +9906,33 @@ } } }, + "url-loader": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", + "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", + "requires": { + "loader-utils": "1.1.0", + "mime": "2.4.0", + "schema-utils": "1.0.0" + }, + "dependencies": { + "mime": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "6.6.2", + "ajv-errors": "1.0.1", + "ajv-keywords": "3.2.0" + } + } + } + }, "url-parse": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", diff --git a/package.json b/package.json index 3dfa158d8..8aa4c01c0 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "awesome-typescript-loader": "^5.2.1", "chai": "^4.2.0", "copy-webpack-plugin": "^4.6.0", - "css-loader": "^2.0.1", + "css-loader": "^2.1.0", "mocha": "^5.2.0", "sass-loader": "^7.1.0", "scss-loader": "0.0.1", @@ -59,6 +59,7 @@ "react-golden-layout": "^1.0.6", "react-jsx-parser": "^1.13.0", "react-mosaic": "0.0.20", + "url-loader": "^1.1.2", "uuid": "^3.3.2" } } diff --git a/src/Main.tsx b/src/Main.tsx index 73fc06941..2770ccff2 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -46,14 +46,14 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { doc2.SetField(KS.X, new NumberField(150)); doc2.SetField(KS.Y, new NumberField(20)); let doc3 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { - x: 450, y: 500 + x: 450, y: 500, title: "cat 1" }); let docset = new Array(doc1, doc2, doc3); let doc4 = Documents.CollectionDocument(docset, { x: 0, y: 400, title: "mini collection" }); let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { - x: 650, y: 500, width: 600, height: 600, title: "cat" + x: 650, y: 500, width: 600, height: 600, title: "cat 2" }); let docset2 = new Array(doc4, doc1, doc3); let doc6 = Documents.CollectionDocument(docset2, { diff --git a/src/util/DragManager.ts b/src/util/DragManager.ts index ca5b6c0ea..5a854c76d 100644 --- a/src/util/DragManager.ts +++ b/src/util/DragManager.ts @@ -2,6 +2,8 @@ import { Opt } from "../fields/Field"; import { DocumentView } from "../views/nodes/DocumentView"; import { DocumentDecorations } from "../DocumentDecorations"; import { SelectionManager } from "./SelectionManager"; +import { CollectionDockingView } from "../views/collections/CollectionDockingView"; +import { Document } from "../fields/Document"; export namespace DragManager { export let rootId = "root"; diff --git a/src/views/collections/CollectionDockingView.scss b/src/views/collections/CollectionDockingView.scss index 43af7c538..249f837f7 100644 --- a/src/views/collections/CollectionDockingView.scss +++ b/src/views/collections/CollectionDockingView.scss @@ -5,9 +5,11 @@ left: 0; overflow: hidden; .flexlayout__layout { - width: 100%; - height: 100%; - position: relative; + left: 0; + top: 0; + right: 0; + bottom: 0; + position: absolute; overflow:hidden; } @@ -79,9 +81,10 @@ .flexlayout__tab { overflow: auto; - position: absolute; + position:absolute; box-sizing: border-box; background-color: #222; + color:black; } .flexlayout__tab_button { @@ -137,7 +140,7 @@ .flexlayout__tab_button:hover .flexlayout__tab_button_trailing, .flexlayout__tab_button--selected .flexlayout__tab_button_trailing{ - //background: transparent url("../images/close_white.png") no-repeat center; + background: transparent url("../../../node_modules/flexlayout-react/images/close_white.png") no-repeat center; } .flexlayout__tab_button_overflow { @@ -150,7 +153,7 @@ font-size: 10px; color:lightgray; font-family: Arial, sans-serif; - //background: transparent url("../images/more.png") no-repeat left; + background: transparent url("../../../node_modules/flexlayout-react/images/more.png") no-repeat left; } .flexlayout__tabset_header @@ -185,12 +188,12 @@ .flexlayout__tabset-selected { - //background-image: linear-gradient(#111, #444); + background-image: linear-gradient(#111, #444); } .flexlayout__tabset-maximized { - //background-image: linear-gradient(#666, #333); + background-image: linear-gradient(#666, #333); } .flexlayout__tab_toolbar { @@ -208,7 +211,7 @@ height:20px; border:none; outline-width: 0; - //background: transparent url("../images/maximize.png") no-repeat center; + background: transparent url("../../../node_modules/flexlayout-react/images/maximize.png") no-repeat center; } .flexlayout__tab_toolbar_button-max { @@ -216,7 +219,7 @@ height:20px; border:none; outline-width: 0; - //background: transparent url("../images/restore.png") no-repeat center; + background: transparent url("../../../node_modules/flexlayout-react/images/restore.png") no-repeat center; } .flexlayout__popup_menu { @@ -339,7 +342,7 @@ .flexlayout__border_button:hover .flexlayout__border_button_trailing, .flexlayout__border_button--selected .flexlayout__border_button_trailing{ - //background: transparent url("../images/close_white.png") no-repeat center; + background: transparent url("../../../node_modules/flexlayout-react/images/close_white.png") no-repeat center; } diff --git a/src/views/collections/CollectionDockingView.tsx b/src/views/collections/CollectionDockingView.tsx index f08bdaab4..8fc8e879b 100644 --- a/src/views/collections/CollectionDockingView.tsx +++ b/src/views/collections/CollectionDockingView.tsx @@ -15,6 +15,7 @@ import 'golden-layout/src/css/goldenlayout-base.css'; import 'golden-layout/src/css/goldenlayout-dark-theme.css'; import * as GoldenLayout from "golden-layout"; import * as ReactDOM from 'react-dom'; +import { DragManager } from "../../util/DragManager"; @observer export class CollectionDockingView extends React.Component { @@ -46,7 +47,11 @@ export class CollectionDockingView extends React.Component var d = { type: 'component', componentName: 'documentViewComponent', componentState: { doc: doc } }; return d; }); - return new GoldenLayout({ content: [ { type: 'row', content: docs } ] }); + return new GoldenLayout({ + settings: { + selectionEnabled: true + }, content: [ { type: 'row', content: docs } ] + }); } constructor(props: CollectionViewProps) { super(props); @@ -114,10 +119,38 @@ export class CollectionDockingView extends React.Component } } + public static myLayout: any = null; + + private static _dragSource: any = null; + private static _dragDiv: any = null; + private static _dragParent: HTMLElement | null = null; + public static StartOtherDrag(dragElement: HTMLDivElement, dragDoc: Document) { + var newItemConfig = { + type: 'component', + componentName: 'documentViewComponent', + componentState: { doc: dragDoc } + }; + const root = document.getElementById(DragManager.rootId); + if (!this._dragDiv) { + if (!root) { + throw new Error("No root element found"); + } + this._dragDiv = document.createElement("div"); + this._dragSource = CollectionDockingView.myLayout.createDragSource(this._dragDiv, newItemConfig); + root.appendChild(this._dragDiv); + } + // var r = dragElement.getBoundingClientRect(); + // var x = root!.getBoundingClientRect(); + //this._dragDiv.style.transform = `translate(${r.left - x.left}px, ${r.top - x.top}px)`; + this._dragSource._itemConfig = newItemConfig; + this._dragParent = dragElement.parentElement; + this._dragDiv.appendChild(dragElement); + } goldenLayoutFactory() { - var myLayout = this.modelForGoldenLayout; + CollectionDockingView.myLayout = this.modelForGoldenLayout; - myLayout.on('stackCreated', function (stack: any) { + CollectionDockingView.myLayout.on('stackCreated', function (stack: any) { + stack.header.controlsContainer.find('.lm_popout').hide(); stack.header.controlsContainer.find('.lm_close') //get the close icon .off('click') //unbind the current click handler .click(function () { @@ -127,7 +160,14 @@ export class CollectionDockingView extends React.Component }); }); - myLayout.on('tabCreated', function (tab: any) { + CollectionDockingView.myLayout.on('tabCreated', function (tab: any) { + if (CollectionDockingView._dragDiv) { + for (var i = 0; i < CollectionDockingView._dragDiv.childElementCount; i++) { + var child = CollectionDockingView._dragDiv.childNodes[ CollectionDockingView._dragDiv.childElementCount - i - 1 ]; + CollectionDockingView._dragDiv.removeChild(child); + CollectionDockingView._dragParent!.appendChild(child); + } + } tab.setTitle(tab.contentItem.config.componentState.doc.Title); tab.closeElement.off('click') //unbind the current click handler .click(function () { @@ -138,7 +178,7 @@ export class CollectionDockingView extends React.Component }); var me = this; - myLayout.registerComponent('documentViewComponent', function (container: any, state: any) { + CollectionDockingView.myLayout.registerComponent('documentViewComponent', function (container: any, state: any) { // bcz: this is crufty // calling html() causes a div tag to be added in the DOM with id 'containingDiv'. // Apparently, we need to wait to allow a live html div element to actually be instantiated. @@ -150,11 +190,11 @@ export class CollectionDockingView extends React.Component ), document.getElementById(containingDiv) - ) + ); }, 0); }); - myLayout.container = this._containerRef.current; - myLayout.init(); + CollectionDockingView.myLayout.container = this._containerRef.current; + CollectionDockingView.myLayout.init(); } @@ -176,7 +216,7 @@ export class CollectionDockingView extends React.Component borderStyle: "solid", borderWidth: `${COLLECTION_BORDER_WIDTH}px`, }}> -
e.preventDefault()} ref={this._containerRef} +