diff options
author | tschicke-brown <tyler_schicke@brown.edu> | 2019-01-26 17:23:42 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-26 17:23:42 -0500 |
commit | f8ce9c45eeba1eccb4244a08e2c752fe4cf39105 (patch) | |
tree | be39c0c927ae4649c8505ef33c7f1c8272974ca2 | |
parent | 122076af3edfd432e6abe3b2571f21034d5c16e5 (diff) | |
parent | ba3c6773a04ea83facab1f67db0025d6185c2c65 (diff) |
Merge pull request #3 from browngraphicslab/move_doc_get_out_the_way
Move doc get out the way
-rw-r--r-- | package-lock.json | 73 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | src/Main.scss | 1 | ||||
-rw-r--r-- | src/Main.tsx | 51 | ||||
-rw-r--r-- | src/documents/Documents.ts | 12 | ||||
-rw-r--r-- | src/fields/Document.ts | 3 | ||||
-rw-r--r-- | src/fields/Key.ts | 1 | ||||
-rw-r--r-- | src/viewmodels/DocumentViewModel.ts | 10 | ||||
-rw-r--r-- | src/views/ContextMenu.scss | 34 | ||||
-rw-r--r-- | src/views/ContextMenu.tsx | 68 | ||||
-rw-r--r-- | src/views/ContextMenuItem.tsx | 17 | ||||
-rw-r--r-- | src/views/freeformcanvas/CollectionFreeFormView.tsx | 182 | ||||
-rw-r--r-- | src/views/freeformcanvas/FreeFormCanvas.scss | 15 | ||||
-rw-r--r-- | src/views/freeformcanvas/FreeFormCanvas.tsx | 90 | ||||
-rw-r--r-- | src/views/nodes/DocumentView.tsx | 166 | ||||
-rw-r--r-- | src/views/nodes/FieldTextBox.scss | 11 | ||||
-rw-r--r-- | src/views/nodes/FieldTextBox.tsx | 2 |
17 files changed, 474 insertions, 263 deletions
diff --git a/package-lock.json b/package-lock.json index 955f0f3ae..7dfe02494 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,16 +4,29 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@fortawesome/fontawesome-common-types": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.12.tgz", + "integrity": "sha512-ISLNpEx6fhJTYYkvBeo/4DHeL5EIA+VybJoOOnH67m6uXt6V6VFizdEN4qchHagNIeZfzI0LnA22gk0wbVPv/g==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.12.tgz", + "integrity": "sha512-cqTfa3vZ+Z9UYQnmLfCOwyLnf0Xcoxkmm/BSaI29Yikzu9zIeD4es7lBZMDqLOXYSEQC+rCr8caxFlGJcJVA+w==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.12" + } + }, "@types/chai": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", - "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", + "integrity": "sha1-G44zthqMCcvh+FEzBxuqDb+fpxo=", "dev": true }, "@types/mocha": { "version": "5.2.5", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.5.tgz", - "integrity": "sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww==", + "integrity": "sha1-ikrM/EA8EkoLr+ip/GGgXsEDIHM=", "dev": true }, "@types/node": { @@ -117,7 +130,7 @@ "@types/react-dom": { "version": "16.0.11", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.0.11.tgz", - "integrity": "sha512-x6zUx9/42B5Kl2Vl9HlopV8JF64wLpX3c+Pst9kc1HgzrsH+mkehe/zmHMQTplIrR48H2gpU7ZqurQolYu8XBA==", + "integrity": "sha1-vRDMsNkmA0P0uaSdT3qDMKXB8IE=", "dev": true, "requires": { "@types/react": "*" @@ -126,7 +139,7 @@ "@types/uuid": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz", - "integrity": "sha512-tPIgT0GUmdJQNSHxp0X2jnpQfBSTfGxUMc/2CXBU2mnyTFVYVa2ojpoQ74w0U2yn2vw3jnC640+77lkFFpdVDw==", + "integrity": "sha1-evaTYPpl7w3stB/RUL9MpcDO/fU=", "requires": { "@types/node": "*" } @@ -579,7 +592,7 @@ "awesome-typescript-loader": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/awesome-typescript-loader/-/awesome-typescript-loader-5.2.1.tgz", - "integrity": "sha512-slv66OAJB8orL+UUaTI3pKlLorwIvS4ARZzYR9iJJyGsEgOqueMfOMdKySWzZ73vIkEe3fcwFgsKMg4d8zyb1g==", + "integrity": "sha1-pB2veEdRX0klzbqjB11h8onpE/w=", "dev": true, "requires": { "chalk": "^2.4.1", @@ -982,7 +995,7 @@ "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "integrity": "sha1-dgqnLPION5XoSxKHfODoNzeqKeU=", "dev": true, "requires": { "assertion-error": "^1.1.0", @@ -1289,7 +1302,7 @@ "copy-webpack-plugin": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz", - "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==", + "integrity": "sha1-5/QN2KaEd9QF3Rt6hUquMksVi64=", "dev": true, "requires": { "cacache": "^10.0.4", @@ -1388,7 +1401,7 @@ "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "integrity": "sha1-uGvV8MJWkJEcdZD8v8IBDVSzzLg=", "dev": true, "requires": { "p-try": "^1.0.0" @@ -1534,7 +1547,7 @@ "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==", + "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", "dev": true, "requires": { "ajv": "^6.1.0", @@ -4165,12 +4178,12 @@ "mobx": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/mobx/-/mobx-5.8.0.tgz", - "integrity": "sha512-NsZB+9bF5j+nv9Qwk6bNeE3np26a4TbTGkMpOLf6o1zXoM9BtHPQn/00px4uZ2AXJXtQML5P4MEWdMm6icMIfQ==" + "integrity": "sha1-z1nq5Lqi/eQ4f/tkYrfM87SXsDw=" }, "mobx-react": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.4.3.tgz", - "integrity": "sha512-WC8yFlwvJ91hy8j6CrydAuFteUafcuvdITFQeHl3LRIf5ayfT/4W3M/byhEYD2BcJWejeXr8y4Rh2H26RunCRQ==", + "integrity": "sha1-Zwm33YlnDEDpgVkUrCyknMAr+0c=", "requires": { "hoist-non-react-statics": "^3.0.0", "react-lifecycles-compat": "^3.0.2" @@ -4179,12 +4192,12 @@ "mobx-react-devtools": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/mobx-react-devtools/-/mobx-react-devtools-6.0.3.tgz", - "integrity": "sha512-PY+lG6XeWaC0DFnDaVC7ImrHJQu7XVXNy4z4fmqHzWc3p+fJisKmaZNwgToO2vJGBghz98Mx2yXUBLw1Ba2mPQ==" + "integrity": "sha1-TVNsjN132fS4H16EFde+3MxqKpk=" }, "mocha": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "integrity": "sha1-bYrlCPWRZ/lA8rWzxKYSrlDJCuY=", "dev": true, "requires": { "browser-stdout": "1.3.1", @@ -4203,13 +4216,13 @@ "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "integrity": "sha1-30boZ9D8Kuxmo0ZitAapzK//Ww8=", "dev": true }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", "dev": true, "requires": { "ms": "2.0.0" @@ -4218,7 +4231,7 @@ "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -4232,7 +4245,7 @@ "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -4398,7 +4411,7 @@ "node-sass": { "version": "4.11.0", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz", - "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==", + "integrity": "sha1-GD+uw5jpy+k7pDNi4naMqYimNpo=", "requires": { "async-foreach": "^0.1.3", "chalk": "^1.1.1", @@ -5206,7 +5219,7 @@ "react": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz", - "integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==", + "integrity": "sha512-ZUj2lkUDLjwJaGu4WD0dYSvsfIyhQt2l/AJDlg4ij+rCDU3fSFKgHWanNovViUoaWHAxgrpft3KGFfvWPZH5LA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -5217,7 +5230,7 @@ "react-dom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.7.0.tgz", - "integrity": "sha512-D0Ufv1ExCAmF38P2Uh1lwpminZFRXEINJe53zRAbm4KPwSyd6DY/uDoS0Blj9jvPpn1+wivKpZYc8aAAN/nAkg==", + "integrity": "sha512-GfG8Vh/jMcnJKDpv7T6O1pS/WVqiocjPQ9o9cscW8bjR9W36DT3Xb4pDZT70t1xyVvX48/NrTQGz0H7I3fCLhQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -5233,7 +5246,7 @@ "react-jsx-parser": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/react-jsx-parser/-/react-jsx-parser-1.13.0.tgz", - "integrity": "sha512-oypIhM30ESZ8UkU0xDmzSV2Mtb2mVvtVnyNzjDxx2h2PCHpYFdDVLx1c15E3ot6nTIVlIh072tWwS3iJ7VVgmg==", + "integrity": "sha1-Dstuus1O41S68+h85SXcJuiPJtQ=", "requires": { "acorn-jsx": "^4.1.1", "react": "^16.4.0" @@ -5618,7 +5631,7 @@ "sass-loader": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", - "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", + "integrity": "sha1-Fv1ROMuLQkv4p1lSihly1yqtBp0=", "dev": true, "requires": { "clone-deep": "^2.0.1", @@ -6321,7 +6334,7 @@ "style-loader": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", - "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "integrity": "sha1-y5FUYG8+dxq2xKtjcCahBJF02SU=", "dev": true, "requires": { "loader-utils": "^1.1.0", @@ -6331,7 +6344,7 @@ "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==", + "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", "dev": true, "requires": { "ajv": "^6.1.0", @@ -6525,7 +6538,7 @@ "ts-node": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", - "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "integrity": "sha1-lWLcLR5tJI0kvFX3c+P2FDN9m68=", "dev": true, "requires": { "arrify": "^1.0.0", @@ -6775,7 +6788,7 @@ "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=" }, "v8-compile-cache": { "version": "2.0.2", @@ -6925,7 +6938,7 @@ "webpack-dev-server": { "version": "3.1.14", "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz", - "integrity": "sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ==", + "integrity": "sha1-YPsim5l/xaCh/GI3QhAwGAlZ1Gk=", "dev": true, "requires": { "ansi-html": "0.0.7", @@ -6963,7 +6976,7 @@ "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", "dev": true, "requires": { "ms": "^2.1.1" @@ -6978,7 +6991,7 @@ "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==", + "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", "dev": true, "requires": { "ajv": "^6.1.0", @@ -6989,7 +7002,7 @@ "webpack-log": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "integrity": "sha1-W3ko4GN1k/EZ0y9iJ8HgrDHhtH8=", "dev": true, "requires": { "ansi-colors": "^3.0.0", diff --git a/package.json b/package.json index 08e999058..71ca3cc8b 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "webpack-dev-server": "^3.1.14" }, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^1.2.12", "@types/prosemirror-commands": "^1.0.1", "@types/prosemirror-history": "^1.0.1", "@types/prosemirror-keymap": "^1.0.1", diff --git a/src/Main.scss b/src/Main.scss index 5fa5b2728..e73f62904 100644 --- a/src/Main.scss +++ b/src/Main.scss @@ -4,6 +4,7 @@ body { height: 100%; overflow: hidden; font-family: 'Hind Siliguri', sans-serif; + margin: 0; } h1 { diff --git a/src/Main.tsx b/src/Main.tsx index 5482314ae..e5302bdee 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -5,24 +5,46 @@ import "normalize.css" import { NodeCollectionStore } from './stores/NodeCollectionStore'; import { StaticTextNodeStore } from './stores/StaticTextNodeStore'; import { VideoNodeStore } from './stores/VideoNodeStore'; -import { FreeFormCanvas } from './views/freeformcanvas/FreeFormCanvas'; -import { Key, KeyStore as KS } from './fields/Key'; +import { Key, KeyStore as KS, KeyStore } from './fields/Key'; import { NumberField } from './fields/NumberField'; import { Document } from './fields/Document'; -import { configure, runInAction } from 'mobx'; +import { configure, runInAction, action } from 'mobx'; import { NodeStore } from './stores/NodeStore'; import { Documents } from './documents/Documents'; import { DocumentDecorations } from './DocumentDecorations'; +import { CollectionFreeFormView } from './views/freeformcanvas/CollectionFreeFormView'; +import { ListField } from './fields/ListField'; +import { DocumentView } from './views/nodes/DocumentView'; +import { DocumentViewModel } from './viewmodels/DocumentViewModel'; +import { ContextMenu } from './views/ContextMenu'; configure({ enforceActions: "observed" }); -const mainNodeCollection = new NodeCollectionStore(); +const mainNodeCollection = new Array<Document>(); +let mainContainer = Documents.CollectionDocument(mainNodeCollection, { + x: 0, y: 0, width: window.screen.width, height: window.screen.height +}) + +window.addEventListener("drop", function(e) { + e.preventDefault(); +}, false) +window.addEventListener("dragover", function(e) { + e.preventDefault(); +}, false) +document.addEventListener("pointerdown", action(function(e: PointerEvent) { + if (!ContextMenu.Instance.intersects(e.pageX, e.pageY)) { + ContextMenu.Instance.clearItems() + } +}), true) + ReactDOM.render(( - <div> - <FreeFormCanvas store={mainNodeCollection} /> + <div style={{display: "grid"}}> + <h1>Dash Web</h1> + <DocumentView Document={mainContainer} ContainingCollectionView={undefined} ContainingDocumentView={undefined}/> <DocumentDecorations /> + <ContextMenu /> </div>), document.getElementById('root')); runInAction(() => { @@ -35,14 +57,19 @@ runInAction(() => { }); let docset = new Array<Document>(doc1, doc2); let doc4 = Documents.CollectionDocument(docset, { - x: 100, y: 400 + x: 0, y: 400 }); let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { x: 650, y: 500 }); - mainNodeCollection.Docs.push(doc1); - mainNodeCollection.Docs.push(doc2); - mainNodeCollection.Docs.push(doc4); - mainNodeCollection.Docs.push(doc3); - mainNodeCollection.Docs.push(doc5); + let mainNodes = mainContainer.GetFieldT(KeyStore.Data, ListField); + if (!mainNodes) { + mainNodes = new ListField<Document>(); + mainContainer.SetField(KeyStore.Data, mainNodes); + } + mainNodes.Data.push(doc1); + mainNodes.Data.push(doc2); + mainNodes.Data.push(doc4); + mainNodes.Data.push(doc3); + mainNodes.Data.push(doc5); });
\ No newline at end of file diff --git a/src/documents/Documents.ts b/src/documents/Documents.ts index a2d2218af..fb7c7c4d9 100644 --- a/src/documents/Documents.ts +++ b/src/documents/Documents.ts @@ -25,6 +25,9 @@ export namespace Documents { if(options.height) { doc.SetFieldValue(KeyStore.Height, options.height, NumberField); } + doc.SetFieldValue(KeyStore.Scale, 1, NumberField); + doc.SetFieldValue(KeyStore.PanX, 0, NumberField); + doc.SetFieldValue(KeyStore.PanY, 0, NumberField); } let textProto:Document; @@ -35,7 +38,7 @@ export namespace Documents { textProto.SetField(KeyStore.Y, new NumberField(0)); textProto.SetField(KeyStore.Width, new NumberField(300)); textProto.SetField(KeyStore.Height, new NumberField(150)); - textProto.SetField(KeyStore.Layout, new TextField("<FieldTextBox doc={doc} fieldKey={DataKey} />")); + textProto.SetField(KeyStore.Layout, new TextField("<FieldTextBox doc={Document} fieldKey={DataKey} />")); textProto.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); } return textProto; @@ -74,11 +77,14 @@ export namespace Documents { function GetCollectionPrototype(): Document { if(!collectionProto) { collectionProto = new Document(); - collectionProto.SetField(KeyStore.X, new NumberField(150)); + collectionProto.SetField(KeyStore.X, new NumberField(0)); collectionProto.SetField(KeyStore.Y, new NumberField(0)); + collectionProto.SetField(KeyStore.Scale, new NumberField(1)); + collectionProto.SetField(KeyStore.PanX, new NumberField(0)); + collectionProto.SetField(KeyStore.PanY, new NumberField(0)); collectionProto.SetField(KeyStore.Width, new NumberField(300)); collectionProto.SetField(KeyStore.Height, new NumberField(300)); - collectionProto.SetField(KeyStore.Layout, new TextField('<CollectionFreeFormView doc={doc} fieldKey={DataKey} isSelected={isSelected}/>')); + collectionProto.SetField(KeyStore.Layout, new TextField('<CollectionFreeFormView Document={Document} fieldKey={DataKey} ContainingDocumentView={ContainingDocumentView}/>')); collectionProto.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.Data])); } return collectionProto; diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 0bba9c21e..6b1cccaf9 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -31,7 +31,8 @@ export class Document extends Field { GetFieldValue<T, U extends { Data: T }>(key: Key, ctor: { new(): U }, defaultVal: T): T { let val = this.GetField(key); - return (val && val instanceof ctor) ? val.Data : defaultVal; + let vval = (val && val instanceof ctor) ? val.Data : defaultVal; + return vval; } SetField(key: Key, field: Opt<Field>): void { diff --git a/src/fields/Key.ts b/src/fields/Key.ts index db30f545d..1f8ba0be5 100644 --- a/src/fields/Key.ts +++ b/src/fields/Key.ts @@ -36,6 +36,7 @@ export namespace KeyStore { export let Y = new Key("Y"); export let PanX = new Key("PanX"); export let PanY = new Key("PanY"); + export let Scale = new Key("Scale"); export let Width = new Key("Width"); export let Height = new Key("Height"); export let Data = new Key("Data"); diff --git a/src/viewmodels/DocumentViewModel.ts b/src/viewmodels/DocumentViewModel.ts index f3154db54..008275f3c 100644 --- a/src/viewmodels/DocumentViewModel.ts +++ b/src/viewmodels/DocumentViewModel.ts @@ -8,14 +8,4 @@ export class DocumentViewModel { get Doc(): Document { return this.doc; } - - private _selected = false; - - get Selected() : boolean { - return this._selected; - } - - set Selected(isSelected: boolean) { - this._selected = isSelected; - } }
\ No newline at end of file diff --git a/src/views/ContextMenu.scss b/src/views/ContextMenu.scss new file mode 100644 index 000000000..234f82eb9 --- /dev/null +++ b/src/views/ContextMenu.scss @@ -0,0 +1,34 @@ +.contextMenu-cont { + position: absolute; + display: flex; + z-index: 1000; + box-shadow: #AAAAAA .2vw .2vw .4vw; +} + +.contextMenu-item { + width: 10vw; + height: 4vh; + background: #DDDDDD; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + transition: all .1s; +} + +.contextMenu-item:hover { + transition: all .1s; + background: #AAAAAA +} + +.contextMenu-description { + font-size: 1.5vw; + text-align: left; + width: 8vw; +}
\ No newline at end of file diff --git a/src/views/ContextMenu.tsx b/src/views/ContextMenu.tsx new file mode 100644 index 000000000..299ce91c6 --- /dev/null +++ b/src/views/ContextMenu.tsx @@ -0,0 +1,68 @@ +import React = require("react"); +import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem"; +import { observable } from "mobx"; +import { observer } from "mobx-react"; +import "./ContextMenu.scss" + +@observer +export class ContextMenu extends React.Component { + static Instance: ContextMenu + + @observable private _items: Array<ContextMenuProps> = [{description:"test", event:(e:React.MouseEvent) => e.preventDefault()}]; + @observable private _pageX: number = 0; + @observable private _pageY: number = 0; + @observable private _display: string = "none"; + + private ref: React.RefObject<HTMLDivElement>; + + constructor(props: Readonly<{}>) { + super(props); + + this.ref = React.createRef() + + ContextMenu.Instance = this; + } + + clearItems() { + this._items = [] + this._display = "none" + } + + addItem(item: ContextMenuProps) { + if (this._items.indexOf(item) === -1) { + this._items.push(item); + } + } + + getItems() { + return this._items; + } + + displayMenu(x: number, y: number) { + this._pageX = x + this._pageY = y + + this._display = "flex" + } + + intersects = (x: number, y: number): boolean => { + if (this.ref.current && this._display !== "none") { + if (x >= this._pageX && x <= this._pageX + this.ref.current.getBoundingClientRect().width) { + if (y >= this._pageY && y <= this._pageY + this.ref.current.getBoundingClientRect().height) { + return true; + } + } + } + return false; + } + + render() { + return( + <div className="contextMenu-cont" style={{left: this._pageX, top: this._pageY, display: this._display }} ref={this.ref}> + {this._items.map(prop => { + return <ContextMenuItem {...prop} key={prop.description}/> + })} + </div> + ) + } +}
\ No newline at end of file diff --git a/src/views/ContextMenuItem.tsx b/src/views/ContextMenuItem.tsx new file mode 100644 index 000000000..beacb44d2 --- /dev/null +++ b/src/views/ContextMenuItem.tsx @@ -0,0 +1,17 @@ +import React = require("react"); +import { ContextMenu } from "./ContextMenu"; + +export interface ContextMenuProps { + description: string; + event: (e: React.MouseEvent<HTMLDivElement>) => void; +} + +export class ContextMenuItem extends React.Component<ContextMenuProps> { + render() { + return( + <div className="contextMenu-item" onClick={this.props.event}> + <div className="contextMenu-description">{this.props.description}</div> + </div> + ) + } +}
\ No newline at end of file diff --git a/src/views/freeformcanvas/CollectionFreeFormView.tsx b/src/views/freeformcanvas/CollectionFreeFormView.tsx index e1aeff534..383d71d83 100644 --- a/src/views/freeformcanvas/CollectionFreeFormView.tsx +++ b/src/views/freeformcanvas/CollectionFreeFormView.tsx @@ -1,8 +1,7 @@ import { observer } from "mobx-react"; import { Key, KeyStore } from "../../fields/Key"; -import "./FreeFormCanvas.scss"; import React = require("react"); -import { action } from "mobx"; +import { action, observable, computed } from "mobx"; import { Document } from "../../fields/Document"; import { DocumentViewModel } from "../../viewmodels/DocumentViewModel"; import { DocumentView } from "../nodes/DocumentView"; @@ -10,80 +9,184 @@ import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; import { SSL_OP_SINGLE_DH_USE } from "constants"; import { DocumentDecorations } from "../../DocumentDecorations"; +import { SelectionManager } from "../../util/SelectionManager"; +import { Documents } from "../../documents/Documents"; +import { ContextMenu } from "../ContextMenu"; +import { Opt } from "../../fields/Field"; interface IProps { fieldKey: Key; - doc: Document; - isSelected: () => boolean; + Document: Document; + ContainingDocumentView: Opt<DocumentView>; } @observer export class CollectionFreeFormView extends React.Component<IProps> { - private _isPointerDown: boolean = false; - constructor(props: IProps) { super(props); } - @action - onPointerDown = (e: React.PointerEvent): void => { - if (!this.props.isSelected()) { - return; - } + @computed + public get active():boolean { + var isSelected = (this.props.ContainingDocumentView != undefined && SelectionManager.IsSelected(this.props.ContainingDocumentView)); + var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this ); + var topMost = this.props.ContainingDocumentView != undefined && this.props.ContainingDocumentView.props.ContainingCollectionView == undefined; + return isSelected || childSelected || topMost; + } - e.stopPropagation(); - if (e.button === 2) { - this._isPointerDown = true; + _lastX: number = 0; + _lastY:number = 0; + @action + onPointerDown = (e: React.PointerEvent): void => + { + if (this.active && e.button === 2) { + e.stopPropagation(); + e.preventDefault(); document.removeEventListener("pointermove", this.onPointerMove); document.addEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); + this._lastX = e.pageX; + this._lastY = e.pageY; } } @action onPointerUp = (e: PointerEvent): void => { + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); e.stopPropagation(); - if (e.button === 2) { - this._isPointerDown = false; - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); + + var topMost = this.props.ContainingDocumentView != undefined && this.props.ContainingDocumentView.props.ContainingCollectionView == undefined; + if (topMost) { + SelectionManager.DeselectAll() } } @action - onPointerMove = (e: PointerEvent): void => { - e.stopPropagation(); - if (!this._isPointerDown) { - return; + onPointerMove = (e: PointerEvent): void => + { + if (!e.cancelBubble) { + e.preventDefault(); + e.stopPropagation(); + const doc = this.props.Document; + let me = this; + let currScale:number = this.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)); + if (me.props.ContainingDocumentView!.props.ContainingDocumentView != undefined) { + let pme = me.props.ContainingDocumentView!.props.ContainingDocumentView!.props.Document; + currScale = pme.GetFieldValue(KeyStore.Scale, NumberField, Number(0)); + } + let x = doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); + let y = doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); + doc.SetFieldValue(KeyStore.PanX, x + (e.pageX - this._lastX)/currScale, NumberField); + doc.SetFieldValue(KeyStore.PanY, y + (e.pageY - this._lastY)/currScale, NumberField); + this._lastX = e.pageX; + this._lastY = e.pageY; + + DocumentDecorations.Instance.forceUpdate() } - const { doc } = this.props; + } - let x = doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); - let y = doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); - doc.SetFieldValue(KeyStore.PanX, x + e.movementX, NumberField); - doc.SetFieldValue(KeyStore.PanY, y + e.movementY, NumberField); + private getLocalPoint(me:DocumentView, inputX: number, inputY: number) { + let ContainerX = inputX; + let ContainerY = inputY; + if (me.props.ContainingDocumentView != undefined) { + let pme = me.props.ContainingDocumentView!; + let {LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy} = this.getLocalPoint(pme, ContainerX, ContainerY); + ContainerX = LocalX; + ContainerY = LocalY; + } - DocumentDecorations.Instance.forceUpdate() + let W = me.props.Document.GetFieldValue(KeyStore.Width, NumberField, Number(0)); + let Xx = me.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0)); + let Yy = me.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0)); + let Ss = me.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)); + let Panxx = me.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); + let Panyy = me.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); + let LocalX = W / 2 - (Xx + Panxx) / Ss + (ContainerX - W / 2) / Ss; + let LocalY = -(Yy + Panyy) / Ss + ContainerY / Ss; + + return {LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY}; } @action - onPointerWheel = (e: React.WheelEvent): void => { + onPointerWheel = (e: React.WheelEvent): void => + { e.stopPropagation(); - let scaleAmount = 1 - (e.deltaY / 1000); - //this.props.store.Scale *= scaleAmount; + let {LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY} = this.getLocalPoint(this.props.ContainingDocumentView!, e.pageX, e.pageY); + + var deltaScale = (1 - (e.deltaY / 1000)) * Ss; + + var newContainerX = LocalX * deltaScale + W/2-W/2 * deltaScale + Panxx + Xx; + var newContainerY = LocalY * deltaScale + Panyy+ Yy; + + let dx = ContainerX - newContainerX; + let dy = ContainerY - newContainerY; + + this.props.Document.SetField(KeyStore.Scale, new NumberField(deltaScale)); + this.props.Document.SetFieldValue(KeyStore.PanX, Panxx+dx, NumberField); + this.props.Document.SetFieldValue(KeyStore.PanY, Panyy+dy, NumberField); + + DocumentDecorations.Instance.forceUpdate() + } + + onDrop = (e: React.DragEvent): void => { + e.stopPropagation() + e.preventDefault() + let fReader = new FileReader() + let file = e.dataTransfer.items[0].getAsFile(); + let that = this; + const panx: number = this.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); + const pany: number = this.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); + let x = e.pageX - panx + let y = e.pageY - pany + + fReader.addEventListener("load", action("drop", (event) => { + if (fReader.result) { + let url = "" + fReader.result; + let doc = Documents.ImageDocument(url, { + x: x, y: y + }) + let docs = that.props.Document.GetFieldT(KeyStore.Data, ListField); + if (!docs) { + docs = new ListField<Document>(); + that.props.Document.SetField(KeyStore.Data, docs) + } + docs.Data.push(doc); + } + }), false) + + if (file) { + fReader.readAsDataURL(file) + } } + @action + removeDocument = (doc: Document): void => { + const value: Document[] = this.props.Document.GetFieldValue(this.props.fieldKey, ListField, []) + if (value.indexOf(doc) !== -1) { + value.splice(value.indexOf(doc), 1) + + SelectionManager.DeselectAll() + ContextMenu.Instance.clearItems() + } + } + + onDragOver = (e: React.DragEvent): void => { + // console.log(e.dataTransfer) + } render() { - const { fieldKey, doc } = this.props; - const value: Document[] = doc.GetFieldValue(fieldKey, ListField, []); - const panx: number = doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); - const pany: number = doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); + const { fieldKey, Document: Document } = this.props; + + const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []); + const panx: number = Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); + const pany: number = Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); + const currScale: number = Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)); + // DocumentDecorations.Instance.forceUpdate() return ( - <div className="border" style={{ borderStyle: "solid", borderWidth: "2px" @@ -92,11 +195,12 @@ export class CollectionFreeFormView extends React.Component<IProps> { width: "100%", height: "calc(100% - 4px)", overflow: "hidden" - }}> - <div className="collectionfreeformview" style={{ transform: `translate(${panx}px, ${pany}px)`, transformOrigin: '50% 50%' }}> + }} onDrop={this.onDrop} onDragOver={this.onDragOver}> + <div className="collectionfreeformview" style={{ transform: `translate(${panx}px, ${pany}px) scale(${currScale}, ${currScale})` , transformOrigin: `left, top`}}> + <div className="node-container"> {value.map(doc => { - return (<DocumentView key={doc.Id} dvm={doc} />); + return (<DocumentView key={doc.Id} ContainingCollectionView={this} Document={doc} ContainingDocumentView={this.props.ContainingDocumentView}/>); })} </div> </div> diff --git a/src/views/freeformcanvas/FreeFormCanvas.scss b/src/views/freeformcanvas/FreeFormCanvas.scss deleted file mode 100644 index 884ef90e6..000000000 --- a/src/views/freeformcanvas/FreeFormCanvas.scss +++ /dev/null @@ -1,15 +0,0 @@ -.freeformcanvas-container { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - overflow: hidden; - - .freeformcanvas { - position: absolute; - top: 0; - left: 0; - } -} - diff --git a/src/views/freeformcanvas/FreeFormCanvas.tsx b/src/views/freeformcanvas/FreeFormCanvas.tsx deleted file mode 100644 index 13e923736..000000000 --- a/src/views/freeformcanvas/FreeFormCanvas.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { observer } from "mobx-react"; -import { Key } from "../../fields/Key"; -import { NodeCollectionStore } from "../../stores/NodeCollectionStore"; -import "./FreeFormCanvas.scss"; -import React = require("react"); -import { action } from "mobx"; -import { Document } from "../../fields/Document"; -import {DocumentViewModel} from "../../viewmodels/DocumentViewModel"; -import {DocumentView} from "../nodes/DocumentView"; -import {TextField} from "../../fields/TextField"; -import {ListField} from "../../fields/ListField"; -import {Field} from "../../fields/Field"; -import { SelectionManager } from "../../util/SelectionManager"; - -interface IProps { - store: NodeCollectionStore; -} - -@observer -export class FreeFormCanvas extends React.Component<IProps> { - - private _isPointerDown: boolean = false; - - constructor(props:IProps) { - super(props); - } - - @action - onPointerDown = (e: React.PointerEvent): void => { - e.stopPropagation(); - if (e.button === 2) { - this._isPointerDown = true; - document.removeEventListener("pointermove", this.onPointerMove); - document.addEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - document.addEventListener("pointerup", this.onPointerUp); - } - - SelectionManager.DeselectAll() - } - - @action - onPointerUp = (e: PointerEvent): void => { - e.stopPropagation(); - if (e.button === 2) { - this._isPointerDown = false; - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - } - - // let doc = this.props.store.Docs[0]; - // let dataField = doc.GetFieldT(KeyStore.Data, TextField); - // let data = dataField ? dataField.Data : ""; - // this.props.store.Docs[0].SetFieldValue(KeyStore.Data, data + " hello", TextField); - } - - @action - onPointerMove = (e: PointerEvent): void => { - e.stopPropagation(); - if (!this._isPointerDown) { - return; - } - - this.props.store.X += e.movementX; - this.props.store.Y += e.movementY; - } - - @action - onPointerWheel = (e: React.WheelEvent): void => { - e.stopPropagation(); - - let scaleAmount = 1 - (e.deltaY / 1000); - this.props.store.Scale *= scaleAmount; - } - - render() { - let store = this.props.store; - return ( - <div className="freeformcanvas-container" onPointerDown={this.onPointerDown} onWheel={this.onPointerWheel} onContextMenu={(e) => e.preventDefault()}> - <div className="freeformcanvas" style={{ transform: store.Transform}}> - <div className="node-container"> - {this.props.store.Docs.map(doc => { - return (<DocumentView key={doc.Id} dvm={doc} />); - })} - </div> - </div> - </div> - ); - } -}
\ No newline at end of file diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx index 772c272bd..33a126a7b 100644 --- a/src/views/nodes/DocumentView.tsx +++ b/src/views/nodes/DocumentView.tsx @@ -1,48 +1,49 @@ import { observer } from "mobx-react"; import React = require("react"); -import { computed, observable } from "mobx"; +import { computed, observable, action } from "mobx"; import { KeyStore, Key } from "../../fields/Key"; import { NumberField } from "../../fields/NumberField"; import { TextField } from "../../fields/TextField"; import { DocumentViewModel } from "../../viewmodels/DocumentViewModel"; import { ListField } from "../../fields/ListField"; import { FieldTextBox } from "../nodes/FieldTextBox" -import { FreeFormCanvas } from "../freeformcanvas/FreeFormCanvas" +import { Document } from "../../fields/Document"; import { CollectionFreeFormView } from "../freeformcanvas/CollectionFreeFormView" import "./NodeView.scss" import { SelectionManager } from "../../util/SelectionManager"; import { DocumentDecorations } from "../../DocumentDecorations"; -import { SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS } from "constants"; -import { DragManager } from "../../util/DragManager"; -import { Document } from "../../fields/Document"; +import { ContextMenu } from "../ContextMenu"; +import { Opt } from "../../fields/Field"; const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? interface IProps { - dvm: Document; + Document: Document; + ContainingCollectionView: Opt<object>; + ContainingDocumentView: Opt<DocumentView> } @observer -class DocumentContents extends React.Component<IProps & {isSelected: () => boolean}> { +class DocumentContents extends React.Component<IProps> { @computed get layout(): string { - return this.props.dvm.GetFieldValue(KeyStore.Layout, TextField, String("<p>Error loading layout data</p>")); + return this.props.Document.GetFieldValue(KeyStore.Layout, TextField, String("<p>Error loading layout data</p>")); } @computed get layoutKeys(): Key[] { - return this.props.dvm.GetFieldValue(KeyStore.LayoutKeys, ListField, new Array<Key>()); + return this.props.Document.GetFieldValue(KeyStore.LayoutKeys, ListField, new Array<Key>()); } @computed get layoutFields(): Key[] { - return this.props.dvm.GetFieldValue(KeyStore.LayoutFields, ListField, new Array<Key>()); + return this.props.Document.GetFieldValue(KeyStore.LayoutFields, ListField, new Array<Key>()); } render() { - let doc = this.props.dvm; + let doc = this.props.Document; let bindings: any = { doc: doc, - isSelected: this.props.isSelected + // isSelected: this.props.isSelected }; for (const key of this.layoutKeys) { bindings[key.Name + "Key"] = key; @@ -54,7 +55,7 @@ class DocumentContents extends React.Component<IProps & {isSelected: () => boole } } return <JsxParser - components={{ FieldTextBox, FreeFormCanvas, CollectionFreeFormView }} + components={{ FieldTextBox, CollectionFreeFormView }} bindings={bindings} jsx={this.layout} showWarnings={true} @@ -69,6 +70,11 @@ class DocumentContents extends React.Component<IProps & {isSelected: () => boole @observer export class DocumentView extends React.Component<IProps> { private _mainCont = React.createRef<HTMLDivElement>(); + private _contextMenuCanOpen = false; + private _downX:number = 0; + private _downY:number = 0; + private _lastX:number = 0; + private _lastY:number = 0; get screenRect(): ClientRect | DOMRect { if (this._mainCont.current) { @@ -79,20 +85,20 @@ export class DocumentView extends React.Component<IProps> { @computed get x(): number { - return this.props.dvm.GetFieldValue(KeyStore.X, NumberField, Number(0)); + return this.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0)); } @computed get y(): number { - return this.props.dvm.GetFieldValue(KeyStore.Y, NumberField, Number(0)); + return this.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0)); } set x(x: number) { - this.props.dvm.SetFieldValue(KeyStore.X, x, NumberField) + this.props.Document.SetFieldValue(KeyStore.X, x, NumberField) } set y(y: number) { - this.props.dvm.SetFieldValue(KeyStore.Y, y, NumberField) + this.props.Document.SetFieldValue(KeyStore.Y, y, NumberField) } @computed @@ -102,33 +108,22 @@ export class DocumentView extends React.Component<IProps> { @computed get width(): number { - return this.props.dvm.GetFieldValue(KeyStore.Width, NumberField, Number(0)); + return this.props.Document.GetFieldValue(KeyStore.Width, NumberField, Number(0)); } set width(w: number) { - this.props.dvm.SetFieldValue(KeyStore.Width, w, NumberField) + this.props.Document.SetFieldValue(KeyStore.Width, w, NumberField) } @computed get height(): number { - return this.props.dvm.GetFieldValue(KeyStore.Height, NumberField, Number(0)); + return this.props.Document.GetFieldValue(KeyStore.Height, NumberField, Number(0)); } set height(h: number) { - this.props.dvm.SetFieldValue(KeyStore.Height, h, NumberField) - } - - @computed - get selected(): boolean { - return SelectionManager.IsSelected(this) - } - - isSelected = (): boolean => { - return this.selected + this.props.Document.SetFieldValue(KeyStore.Height, h, NumberField) } - private _isPointerDown = false; - componentDidMount() { // if(this._mainCont.current) { // DragManager.MakeDraggable(this._mainCont.current, { @@ -141,40 +136,59 @@ export class DocumentView extends React.Component<IProps> { // } } + @computed + get active() : boolean { + return SelectionManager.IsSelected(this) || (this.props.ContainingCollectionView instanceof CollectionFreeFormView && this.props.ContainingCollectionView.active); + } + onPointerDown = (e: React.PointerEvent): void => { - // return; - e.stopPropagation(); - if (e.button === 2) { - this._isPointerDown = true; - document.removeEventListener("pointermove", this.onPointerMove); - document.addEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - document.addEventListener("pointerup", this.onPointerUp); - } else { - SelectionManager.SelectDoc(this, e.ctrlKey) - } + this._downX = e.pageX; + this._downY = e.pageY; + this._lastX = e.pageX; + this._lastY = e.pageY; + this._contextMenuCanOpen = e.button == 2; + document.removeEventListener("pointermove", this.onPointerMove); + document.addEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + document.addEventListener("pointerup", this.onPointerUp); } onPointerUp = (e: PointerEvent): void => { - e.stopPropagation(); - if (e.button === 2) { + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + if (!e.cancelBubble) { + e.stopPropagation(); e.preventDefault(); - this._isPointerDown = false; - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - DocumentDecorations.Instance.opacity = 1 + DocumentDecorations.Instance.opacity = 1; + if (this._downX == e.pageX && this._downY == e.pageY) { + SelectionManager.SelectDoc(this, e.ctrlKey) + } } } onPointerMove = (e: PointerEvent): void => { - e.stopPropagation(); - e.preventDefault(); - if (!this._isPointerDown) { - return; + if (this.active && !e.cancelBubble) { + e.stopPropagation(); + e.preventDefault(); + this._contextMenuCanOpen = false + let me = this; + var dx = e.pageX - this._lastX; + var dy = e.pageY - this._lastY; + this._lastX = e.pageX; + this._lastY = e.pageY; + let currScale:number = 1; + if (me.props.ContainingDocumentView != undefined) { + let pme = me.props.ContainingDocumentView!.props.Document; + currScale = pme.GetFieldValue(KeyStore.Scale, NumberField, Number(0)); + if (me.props.ContainingDocumentView!.props.ContainingDocumentView != undefined) { + let pme = me.props.ContainingDocumentView!.props.ContainingDocumentView!.props.Document; + currScale *= pme.GetFieldValue(KeyStore.Scale, NumberField, Number(0)); + } + } + this.x += dx/currScale; + this.y += dy/currScale; + DocumentDecorations.Instance.opacity = 0; } - this.x += e.movementX; - this.y += e.movementY; - //DocumentDecorations.Instance.opacity = 0 } onDragStart = (e: React.DragEvent<HTMLDivElement>): void => { @@ -184,6 +198,36 @@ export class DocumentView extends React.Component<IProps> { } } + onClick = (e: React.MouseEvent): void => { } + + deleteClicked = (e: React.MouseEvent): void => { + if (this.props.ContainingCollectionView instanceof CollectionFreeFormView) { + this.props.ContainingCollectionView.removeDocument(this.props.Document) + } + } + + @action + onContextMenu = (e: React.MouseEvent): void => { + e.preventDefault() + + if (!this._contextMenuCanOpen) { + return; + } + + var topMost = this.props.ContainingCollectionView == undefined; + if (topMost) { + ContextMenu.Instance.clearItems() + } + else { + // DocumentViews should stop propogation of this event + e.stopPropagation(); + + ContextMenu.Instance.clearItems(); + ContextMenu.Instance.addItem({description: "Delete", event: this.deleteClicked}) + ContextMenu.Instance.displayMenu(e.pageX, e.pageY) + } + } + render() { return ( <div className="node" ref={this._mainCont} style={{ @@ -191,12 +235,10 @@ export class DocumentView extends React.Component<IProps> { width: this.width, height: this.height, }} - onContextMenu={ - (e) => { - e.preventDefault() - }} - onPointerDown={this.onPointerDown}> - <DocumentContents dvm={this.props.dvm} isSelected={this.isSelected} /> + onContextMenu={this.onContextMenu} + onPointerDown={this.onPointerDown} + onClick={this.onClick}> + <DocumentContents {...this.props} /> </div> ); } diff --git a/src/views/nodes/FieldTextBox.scss b/src/views/nodes/FieldTextBox.scss index 2885caa4c..b6ce2fabc 100644 --- a/src/views/nodes/FieldTextBox.scss +++ b/src/views/nodes/FieldTextBox.scss @@ -1,3 +1,14 @@ +.ProseMirror { + margin-top: -1em; + width: 100%; + height: 100%; +} + .ProseMirror:focus { outline: none !important +} + +.fieldTextBox-cont { + background: white; + padding: 1vw; }
\ No newline at end of file diff --git a/src/views/nodes/FieldTextBox.tsx b/src/views/nodes/FieldTextBox.tsx index 2cd55e26e..3b8743627 100644 --- a/src/views/nodes/FieldTextBox.tsx +++ b/src/views/nodes/FieldTextBox.tsx @@ -113,6 +113,6 @@ export class FieldTextBox extends React.Component<IProps> { } render() { - return (<div ref={this._ref} />) + return (<div className="fieldTextBox-cont" ref={this._ref} />) } }
\ No newline at end of file |