aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json73
-rw-r--r--package.json1
-rw-r--r--src/Main.scss1
-rw-r--r--src/Main.tsx51
-rw-r--r--src/documents/Documents.ts12
-rw-r--r--src/fields/Document.ts3
-rw-r--r--src/fields/Key.ts1
-rw-r--r--src/viewmodels/DocumentViewModel.ts10
-rw-r--r--src/views/ContextMenu.scss34
-rw-r--r--src/views/ContextMenu.tsx68
-rw-r--r--src/views/ContextMenuItem.tsx17
-rw-r--r--src/views/freeformcanvas/CollectionFreeFormView.tsx182
-rw-r--r--src/views/freeformcanvas/FreeFormCanvas.scss15
-rw-r--r--src/views/freeformcanvas/FreeFormCanvas.tsx90
-rw-r--r--src/views/nodes/DocumentView.tsx166
-rw-r--r--src/views/nodes/FieldTextBox.scss11
-rw-r--r--src/views/nodes/FieldTextBox.tsx2
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