From 1f038048612e01d0ada6deb9ff2a056cb8d13702 Mon Sep 17 00:00:00 2001 From: Eleanor Eng Date: Mon, 11 Mar 2019 17:32:49 -0400 Subject: some changes --- src/client/views/nodes/FormattedTextBox.tsx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 8b3deeb8b..baedf0852 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -119,17 +119,18 @@ export class FormattedTextBox extends React.Component { specificContextMenu = (e: React.MouseEvent): void => { ContextMenu.Instance.addItem({ description: "Text Capability", event: this.textCapability }); - // ContextMenu.Instance.addItem({ - // description: "Submenu", - // items: [ - // { - // description: "item 1", event: - // }, - // { - // description: "item 2", event: - // } - // ] - // }) + ContextMenu.Instance.addItem({ + description: "Submenu", subitems: + [{ description: "Sub 1", event: this.textCapability }] + // [{ description: "Sub 2", event: this.textCapability }] + // { + // description: "item 1", event: + // }, + // { + // description: "item 2", event: + // } + // ] + }) // e.stopPropagation() } -- cgit v1.2.3-70-g09d2 From 9351426356e06a5c6a7777b1edd118273e29072e Mon Sep 17 00:00:00 2001 From: Eleanor Eng Date: Tue, 12 Mar 2019 17:45:57 -0400 Subject: working submenu; dimensions use vw, vh --- package-lock.json | 236 +++++++++++++++------------- src/client/views/ContextMenu.scss | 1 - src/client/views/ContextMenu.tsx | 6 +- src/client/views/nodes/FormattedTextBox.tsx | 21 +-- 4 files changed, 140 insertions(+), 124 deletions(-) (limited to 'src/client/views/nodes') diff --git a/package-lock.json b/package-lock.json index 75c02628e..8c9bf9c0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1138,7 +1138,7 @@ }, "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -1655,7 +1655,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -1692,7 +1692,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -1731,7 +1731,7 @@ }, "buffer": { "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { @@ -1852,7 +1852,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "requires": { "camelcase": "^2.0.0", @@ -2282,7 +2282,7 @@ }, "content-disposition": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "resolved": "http://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" }, "content-type": { @@ -2401,7 +2401,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -2414,7 +2414,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -2540,7 +2540,7 @@ }, "d": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { @@ -2763,7 +2763,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { @@ -3306,7 +3306,7 @@ "dependencies": { "array-flatten": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "statuses": { @@ -3500,7 +3500,7 @@ }, "finalhandler": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", @@ -3574,14 +3574,18 @@ }, "dependencies": { "readable-stream": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", - "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } } } @@ -3703,24 +3707,24 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "resolved": false, "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "optional": true, "requires": { @@ -3730,12 +3734,12 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", @@ -3744,34 +3748,34 @@ }, "chownr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "resolved": false, "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "optional": true }, "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "resolved": false, "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "optional": true, "requires": { @@ -3780,25 +3784,25 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "resolved": false, "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "resolved": false, "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "optional": true, "requires": { @@ -3807,13 +3811,13 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "requires": { @@ -3829,7 +3833,7 @@ }, "glob": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "resolved": false, "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "optional": true, "requires": { @@ -3843,13 +3847,13 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "resolved": false, "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "optional": true, "requires": { @@ -3858,7 +3862,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "optional": true, "requires": { @@ -3867,7 +3871,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "optional": true, "requires": { @@ -3877,18 +3881,18 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" @@ -3896,13 +3900,13 @@ }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" @@ -3910,12 +3914,12 @@ }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minipass": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "resolved": false, "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "requires": { "safe-buffer": "^5.1.2", @@ -3924,7 +3928,7 @@ }, "minizlib": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "resolved": false, "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "optional": true, "requires": { @@ -3933,7 +3937,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -3941,13 +3945,13 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "optional": true }, "needle": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", + "resolved": false, "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", "optional": true, "requires": { @@ -3958,7 +3962,7 @@ }, "node-pre-gyp": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz", + "resolved": false, "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==", "optional": true, "requires": { @@ -3976,7 +3980,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "optional": true, "requires": { @@ -3986,13 +3990,13 @@ }, "npm-bundled": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", + "resolved": false, "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==", "optional": true }, "npm-packlist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.2.0.tgz", + "resolved": false, "integrity": "sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ==", "optional": true, "requires": { @@ -4002,7 +4006,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "optional": true, "requires": { @@ -4014,18 +4018,18 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" @@ -4033,19 +4037,19 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "optional": true, "requires": { @@ -4055,19 +4059,19 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "optional": true }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "resolved": false, "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "optional": true, "requires": { @@ -4079,7 +4083,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "optional": true } @@ -4087,7 +4091,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "optional": true, "requires": { @@ -4102,7 +4106,7 @@ }, "rimraf": { "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "resolved": false, "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "optional": true, "requires": { @@ -4111,42 +4115,42 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": false, "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "optional": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, "semver": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "resolved": false, "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", @@ -4156,7 +4160,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "optional": true, "requires": { @@ -4165,7 +4169,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -4173,13 +4177,13 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "optional": true }, "tar": { "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "resolved": false, "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "optional": true, "requires": { @@ -4194,13 +4198,13 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "resolved": false, "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "optional": true, "requires": { @@ -4209,12 +4213,12 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "resolved": false, "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" } } @@ -4640,7 +4644,7 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { "depd": "~1.1.2", @@ -4943,7 +4947,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { "kind-of": "^3.0.2" @@ -4987,7 +4991,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { "kind-of": "^3.0.2" @@ -5466,7 +5470,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { "graceful-fs": "^4.1.2", @@ -5767,7 +5771,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { @@ -5799,7 +5803,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "requires": { "camelcase-keys": "^2.0.0", @@ -5965,7 +5969,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -6243,7 +6247,7 @@ }, "next-tick": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, @@ -6302,7 +6306,7 @@ }, "semver": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" }, "tar": { @@ -9685,12 +9689,12 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "osenv": { @@ -9856,7 +9860,7 @@ }, "path-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", "dev": true }, @@ -9875,7 +9879,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { @@ -10888,7 +10892,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -11149,7 +11153,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -11371,7 +11375,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -11929,11 +11933,31 @@ "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -11941,7 +11965,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -11957,7 +11981,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-indent": { @@ -12393,7 +12417,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -12798,7 +12822,7 @@ }, "vm-browserify": { "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "resolved": "http://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", "dev": true, "requires": { @@ -13587,7 +13611,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 82e736520..bfd643caf 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -12,7 +12,6 @@ z-index: 1000; box-shadow: #AAAAAA .2vw .2vw .4vw; flex-direction: column; - left: 100%; //should make this appear 100% to the right of the parent element (the original context menu) } .contextMenu-item { diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 8a8403c62..ce9023352 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -9,7 +9,6 @@ export class ContextMenu extends React.Component { static Instance: ContextMenu @observable private _items: Array = [{ description: "test", event: (e: React.MouseEvent) => e.preventDefault() }]; - //need to add a subitems component? @observable private _pageX: number = 0; @observable private _pageY: number = 0; @observable private _display: string = "none"; @@ -37,6 +36,7 @@ export class ContextMenu extends React.Component { if (this._items.indexOf(item) === -1) { this._items.push(item); } + console.log(`After adding, there are ${this._items.length} items`); } getItems() { @@ -81,6 +81,4 @@ export class ContextMenu extends React.Component { onChange = (e: React.ChangeEvent) => { this._searchString = e.target.value; } -} - -// \ No newline at end of file +} \ No newline at end of file diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 411b43cd5..dfc7e9096 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -122,22 +122,17 @@ export class FormattedTextBox extends React.Component { textCapability = (e: React.MouseEvent): void => { } + @action specificContextMenu = (e: React.MouseEvent): void => { ContextMenu.Instance.addItem({ description: "Text Capability", event: this.textCapability }); ContextMenu.Instance.addItem({ - description: "Submenu", subitems: - [{ description: "Sub 1", event: this.textCapability }] - // [{ description: "Sub 2", event: this.textCapability }] - // { - // description: "item 1", event: - // }, - // { - // description: "item 2", event: - // } - // ] - }) - // e.stopPropagation() - + description: "Submenu", subitems: [ + { description: "Subitem 1", event: this.textCapability }, + { description: "Subitem 2", event: this.textCapability }, + { description: "Subitem 3", event: this.textCapability }, + { description: "Submenu", subitems: [{ description: "Inner Subitem", event: this.textCapability }] } + ] + }); } onPointerWheel = (e: React.WheelEvent): void => { -- cgit v1.2.3-70-g09d2 From 02f0311a868decd92af53d1ffbb6f03bdaa912db Mon Sep 17 00:00:00 2001 From: Eleanor Eng Date: Sat, 16 Mar 2019 16:53:46 -0400 Subject: submenus overlapping --- src/client/views/ContextMenu.scss | 2 +- src/client/views/ContextMenu.tsx | 11 ++++++++++- src/client/views/ContextMenuItem.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index bcf856d48..265cdefca 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -16,7 +16,7 @@ .contextMenu-item { width: 10vw; //10vw - height: auto; //4vh + height: 2vh; background: #DDDDDD; display: flex; justify-content: left; diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 31c165373..73bad477b 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -3,6 +3,11 @@ import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem"; import { observable, action } from "mobx"; import { observer } from "mobx-react" import "./ContextMenu.scss" +import { library } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSearch } from '@fortawesome/free-solid-svg-icons'; + +library.add(faSearch); @observer export class ContextMenu extends React.Component { @@ -67,7 +72,11 @@ export class ContextMenu extends React.Component { render() { return (
- +
+ + {/* */} + +
{this._items.filter(prop => { return prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1; }).map(prop => { diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 67bbc3082..6bd370152 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -38,7 +38,7 @@ export class ContextMenuItem extends React.Component { else { let submenu = null; if (this.overItem) { - submenu = (
+ submenu = (
{this._items.map(prop => { return })} diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index dfc7e9096..e402392a7 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -126,7 +126,7 @@ export class FormattedTextBox extends React.Component { specificContextMenu = (e: React.MouseEvent): void => { ContextMenu.Instance.addItem({ description: "Text Capability", event: this.textCapability }); ContextMenu.Instance.addItem({ - description: "Submenu", subitems: [ + description: "Sub", subitems: [ { description: "Subitem 1", event: this.textCapability }, { description: "Subitem 2", event: this.textCapability }, { description: "Subitem 3", event: this.textCapability }, -- cgit v1.2.3-70-g09d2 From 7db0071a1f1232112597176b0b077e6b7e37679d Mon Sep 17 00:00:00 2001 From: Eleanor Eng Date: Mon, 18 Mar 2019 19:00:13 -0400 Subject: Added icons --- src/client/views/ContextMenu.scss | 12 +++++--- src/client/views/ContextMenu.tsx | 14 +++++---- src/client/views/ContextMenuItem.tsx | 11 ++++++-- src/client/views/collections/CollectionPDFView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 19 ++++++++++--- src/client/views/nodes/DocumentView.tsx | 33 ++++++++++++++++------ src/client/views/nodes/FormattedTextBox.tsx | 18 +++++++----- src/client/views/nodes/ImageBox.tsx | 2 +- 8 files changed, 77 insertions(+), 34 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 43e5033fd..5c40c3c43 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -15,10 +15,9 @@ } .contextMenu-item { - width: 10vw; //10vw - height: 2vh; - background: #DDDDDD; - display: flex; + width: 11vw; //10vw + height: 2.5vh; //2vh + background: #DDDDDD; // display: flex; justify-content: left; align-items: center; -webkit-touch-callout: none; @@ -46,4 +45,9 @@ font-size: 1.5vw; text-align: left; width: 8vw; + display: inline; //need this? +} + +.icon-background { + background-color: #DDDDDD; } \ No newline at end of file diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 2396ce762..39ccb55b0 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -13,7 +13,7 @@ library.add(faSearch); export class ContextMenu extends React.Component { static Instance: ContextMenu - @observable private _items: Array = [{ description: "test", event: (e: React.MouseEvent) => e.preventDefault() }]; + @observable private _items: Array = [{ description: "test", event: (e: React.MouseEvent) => e.preventDefault(), icon: "smile" }]; @observable private _pageX: number = 0; @observable private _pageY: number = 0; @observable private _display: string = "none"; @@ -72,11 +72,13 @@ export class ContextMenu extends React.Component { render() { return (
-
- {/* */} - - -
+ + + + + + + {this._items.filter(prop => { return prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1; }).map(prop => { diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 6b17c5c19..80d9ff6a5 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -1,10 +1,13 @@ import React = require("react"); import { observable, action } from "mobx"; import { observer } from "mobx-react"; +import { library, IconProp } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; export interface OriginalMenuProps { description: string; event: (e: React.MouseEvent) => void; + icon: IconProp; //maybe should be optional (icon?) } export interface SubmenuProps { @@ -17,8 +20,6 @@ export type ContextMenuProps = OriginalMenuProps | SubmenuProps; @observer export class ContextMenuItem extends React.Component { @observable private _items: Array = []; - @observable private _pageX: number = 0; - @observable private _pageY: number = 0; @observable private overItem = false; constructor(props: ContextMenuProps) { @@ -32,13 +33,17 @@ export class ContextMenuItem extends React.Component { if ("event" in this.props) { return (
+ + + +
{this.props.description}
) } else { let submenu = null; if (this.overItem) { - submenu = (
+ submenu = (
{this._items.map(prop => { return })} diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index f22c07060..bcb1cd2f7 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -41,7 +41,7 @@ export class CollectionPDFView extends React.Component { specificContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "PDFOptions", event: () => { } }); + ContextMenu.Instance.addItem({ description: "PDFOptions", event: () => { }, icon: "file-pdf" }); } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 548a51bf1..b76426429 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -13,6 +13,17 @@ import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionViewProps } from "./CollectionViewBase"; import { CollectionTreeView } from "./CollectionTreeView"; import { Field, FieldId } from "../../../fields/Field"; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faTh } from '@fortawesome/free-solid-svg-icons'; +import { faTree } from '@fortawesome/free-solid-svg-icons'; +import { faSquare } from '@fortawesome/free-solid-svg-icons'; +import { faProjectDiagram } from '@fortawesome/free-solid-svg-icons'; + +library.add(faTh); +library.add(faTree); +library.add(faSquare); +library.add(faProjectDiagram); export enum CollectionViewType { Invalid, @@ -96,10 +107,10 @@ export class CollectionView extends React.Component { specificContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "Freeform", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) }) - ContextMenu.Instance.addItem({ description: "Schema", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema) }) - ContextMenu.Instance.addItem({ description: "Treeview", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree) }) - ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) }) + ContextMenu.Instance.addItem({ description: "Freeform", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform), icon: "project-diagram" }) + ContextMenu.Instance.addItem({ description: "Schema", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema), icon: "th" }) + ContextMenu.Instance.addItem({ description: "Treeview", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree), icon: "tree" }) + ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking), icon: "square" }) } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index dc793c16d..53a3aaa18 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -27,6 +27,23 @@ import React = require("react"); import { TextField } from "../../../fields/TextField"; import { DocumentManager } from "../../util/DocumentManager"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? +import { library } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faTrash } from '@fortawesome/free-solid-svg-icons'; +import { faExpandArrowsAlt } from '@fortawesome/free-solid-svg-icons'; +import { faCompressArrowsAlt } from '@fortawesome/free-solid-svg-icons'; +import { faLayerGroup } from '@fortawesome/free-solid-svg-icons'; +import { faAlignCenter } from '@fortawesome/free-solid-svg-icons'; +import { faCaretSquareRight } from '@fortawesome/free-solid-svg-icons'; +import { faSquare } from '@fortawesome/free-solid-svg-icons'; + +library.add(faTrash); +library.add(faExpandArrowsAlt); +library.add(faCompressArrowsAlt); +library.add(faLayerGroup); +library.add(faAlignCenter); +library.add(faCaretSquareRight); +library.add(faSquare); export interface DocumentViewProps { @@ -212,14 +229,14 @@ export class DocumentView extends React.Component { fullScreenClicked = (e: React.MouseEvent): void => { CollectionDockingView.Instance.OpenFullScreen(this.props.Document); ContextMenu.Instance.clearItems(); - ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked }); + ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked, icon: "compress-arrows-alt" }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) } closeFullScreenClicked = (e: React.MouseEvent): void => { CollectionDockingView.Instance.CloseFullScreen(); ContextMenu.Instance.clearItems(); - ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) + ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked, icon: "expand-arrows-alt" }) ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) } @@ -261,18 +278,18 @@ export class DocumentView extends React.Component { } e.preventDefault() - ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }) - ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked }) - ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) }) - ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) }) - //ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) }) + ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked, icon: "expand-arrows-alt" }) + ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked, icon: "layer-group" }) + ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document), icon: "align-center" }) + ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document), icon: "caret-square-right" }) + ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking), icon: "square" }) ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) if (!this.topMost) { // DocumentViews should stop propagation of this event e.stopPropagation(); } - ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked }) + ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" }) ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) SelectionManager.SelectDoc(this, e.ctrlKey); } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index e402392a7..7a8dbddcc 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -14,9 +14,13 @@ import { Plugin } from 'prosemirror-state' import { Decoration, DecorationSet } from 'prosemirror-view' import { TooltipTextMenu } from "../../util/TooltipTextMenu" import { ContextMenu } from "../../views/ContextMenu"; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faEdit } from '@fortawesome/free-solid-svg-icons'; +import { faSmile } from '@fortawesome/free-solid-svg-icons'; - - +library.add(faEdit); +library.add(faSmile); // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // @@ -124,13 +128,13 @@ export class FormattedTextBox extends React.Component { @action specificContextMenu = (e: React.MouseEvent): void => { - ContextMenu.Instance.addItem({ description: "Text Capability", event: this.textCapability }); + ContextMenu.Instance.addItem({ description: "Text Capability", event: this.textCapability, icon: "edit" }); ContextMenu.Instance.addItem({ description: "Sub", subitems: [ - { description: "Subitem 1", event: this.textCapability }, - { description: "Subitem 2", event: this.textCapability }, - { description: "Subitem 3", event: this.textCapability }, - { description: "Submenu", subitems: [{ description: "Inner Subitem", event: this.textCapability }] } + { description: "Subitem 1", event: this.textCapability, icon: "smile" }, + { description: "Subitem 2", event: this.textCapability, icon: "smile" }, + { description: "Subitem 3", event: this.textCapability, icon: "smile" }, + { description: "Submenu", subitems: [{ description: "Inner Subitem", event: this.textCapability, icon: "smile" }] } ] }); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 30910fb1f..62ecea583 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -94,7 +94,7 @@ export class ImageBox extends React.Component { } specificContextMenu = (e: React.MouseEvent): void => { - ContextMenu.Instance.addItem({ description: "Image Capability", event: this.imageCapability }); + ContextMenu.Instance.addItem({ description: "Image Capability", event: this.imageCapability, icon: "smile" }); } render() { -- cgit v1.2.3-70-g09d2 From 19fca408a19c5f7a759ff6c3bfefe27b96ec3563 Mon Sep 17 00:00:00 2001 From: Eleanor Eng Date: Tue, 19 Mar 2019 17:51:25 -0400 Subject: contextmenu --- src/client/views/ContextMenu.scss | 2 +- src/client/views/ContextMenuItem.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 1 - src/client/views/nodes/DocumentView.tsx | 1 - src/client/views/nodes/FormattedTextBox.tsx | 1 - src/client/views/nodes/ImageBox.tsx | 1 - 6 files changed, 2 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index e5d41fcb6..8bc7708f7 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -18,7 +18,7 @@ width: 11vw; //10vw height: 2.5vh; //2vh background: #DDDDDD; - display: flex; + display: flex; //comment out to allow search icon to be inline with search text justify-content: left; align-items: center; -webkit-touch-callout: none; diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 80d9ff6a5..fac7342aa 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -1,7 +1,7 @@ import React = require("react"); import { observable, action } from "mobx"; import { observer } from "mobx-react"; -import { library, IconProp } from '@fortawesome/fontawesome-svg-core'; +import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; export interface OriginalMenuProps { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index b76426429..d0e2162b1 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -14,7 +14,6 @@ import { CollectionViewProps } from "./CollectionViewBase"; import { CollectionTreeView } from "./CollectionTreeView"; import { Field, FieldId } from "../../../fields/Field"; import { library } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faTh } from '@fortawesome/free-solid-svg-icons'; import { faTree } from '@fortawesome/free-solid-svg-icons'; import { faSquare } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 53a3aaa18..907762837 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -28,7 +28,6 @@ import { TextField } from "../../../fields/TextField"; import { DocumentManager } from "../../util/DocumentManager"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? import { library } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faTrash } from '@fortawesome/free-solid-svg-icons'; import { faExpandArrowsAlt } from '@fortawesome/free-solid-svg-icons'; import { faCompressArrowsAlt } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7a8dbddcc..648037e31 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -15,7 +15,6 @@ import { Decoration, DecorationSet } from 'prosemirror-view' import { TooltipTextMenu } from "../../util/TooltipTextMenu" import { ContextMenu } from "../../views/ContextMenu"; import { library } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faEdit } from '@fortawesome/free-solid-svg-icons'; import { faSmile } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 62ecea583..7532e23c8 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,4 +1,3 @@ - import { action, observable } from 'mobx'; import { observer } from "mobx-react"; import Lightbox from 'react-image-lightbox'; -- cgit v1.2.3-70-g09d2 From 6e767972574c9cd8a2cd1e10a8fa327839ca3525 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 16 May 2019 01:17:44 -0400 Subject: changes to make maximizing stuff apply to data documents. problem with zooiming after resizing a summarized doc --- src/client/views/DocumentDecorations.tsx | 4 ++-- src/client/views/TemplateMenu.tsx | 2 +- src/client/views/Templates.tsx | 15 ++++++------ .../collections/collectionFreeForm/MarqueeView.tsx | 8 ++++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 28 ++++++++++------------ 5 files changed, 28 insertions(+), 29 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8d85f7e2c..b2c65a31f 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -263,7 +263,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> topDocView.props.Document.subBulletDocs = undefined; } else { topDocView.addTemplate(Templates.Bullet); - topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document)); + topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); } } } @@ -285,7 +285,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> iconDoc.height = Number(MINIMIZED_ICON_SIZE); iconDoc.x = NumCast(doc.x); iconDoc.y = NumCast(doc.y) - 24; - iconDoc.maximizedDocs = new List(selected.map(s => s.props.Document)); + iconDoc.maximizedDocs = new List(selected.map(s => s.props.Document.proto!)); doc.minimizedDoc = iconDoc; selected[0].props.addDocument && selected[0].props.addDocument(iconDoc, false); return iconDoc; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 22c4edc25..cfe1b0663 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -46,7 +46,7 @@ export class TemplateMenu extends React.Component { if (template.Name == "Bullet") { let topDocView = this.props.docs[0]; topDocView.addTemplate(template); - topDocView.props.Document.subBulletDocs = new List(this.props.docs.filter(v => v !== topDocView).map(v => v.props.Document)); + topDocView.props.Document.subBulletDocs = new List(this.props.docs.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); } else { this.props.docs.map(d => d.addTemplate(template)); } diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index ca0c04d1b..f0ee2856b 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -62,18 +62,19 @@ export namespace Templates {
` ); export const Bullet = new Template("Bullet", TemplatePosition.InnerTop, - `
{layout}
-
- -
+ `
+
{layout}
+
+ +
` ); export function ImageOverlay(width: number, height: number, field: string = "thumbnail") { return (`
-
{layout}
-
+
{layout}
+
`); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 865bae729..c063115e7 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -264,7 +264,6 @@ export class MarqueeView extends React.Component // SelectionManager.DeselectAll(); if (e.key === "s" || e.key === "r" || e.key === "p") { e.preventDefault(); - let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); let dataUrl = await htmlToImage.toPng(this._mainCont.current!, { width: bounds.width, height: bounds.height, quality: 1 }); @@ -272,12 +271,15 @@ export class MarqueeView extends React.Component summary.proto!.templates = new List([Templates.ImageOverlay(Math.min(50, bounds.width), bounds.height * Math.min(50, bounds.width) / bounds.width, "thumbnail")]); if (e.key === "s" || e.key === "p") { - summary.proto!.maximizeOnRight = true; + // summary.proto!.maximizeOnRight = true; newCollection.proto!.summaryDoc = summary; selected = [newCollection]; + newCollection.proto!.isMinimized = true; + this.props.addDocument(newCollection, false); } - summary.proto!.summarizedDocs = new List(selected); + summary.proto!.summarizedDocs = new List(selected.map(s => s.proto!)); //summary.proto!.isButton = true; + let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); selected.map(summarizedDoc => { let maxx = NumCast(summarizedDoc.x, undefined); let maxy = NumCast(summarizedDoc.y, undefined); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 631bf1ba8..03538ae66 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -87,7 +87,8 @@ export class CollectionFreeFormDocumentView extends DocComponent { let now = Date.now(); @@ -115,13 +116,13 @@ export class CollectionFreeFormDocumentView extends DocComponent([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), isMinimized ? 1 : 0]) + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]) } } }); @@ -194,7 +190,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { maxDoc.isMinimized = false; if (!CollectionDockingView.Instance.CloseRightSplit(maxDoc)) { - CollectionDockingView.Instance.AddRightSplit(maxDoc.proto ? Doc.MakeDelegate(maxDoc.proto) : maxDoc); + CollectionDockingView.Instance.AddRightSplit(Doc.MakeDelegate(maxDoc)); } }); } } else { - this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(maxDoc, false)); + //if (altKey) this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(maxDoc, false)); this.toggleIcon(expandedDocs); } } -- cgit v1.2.3-70-g09d2 From 22d9a6540f2994331c397154f6a1fecd6e46ef8c Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 16 May 2019 11:19:50 -0400 Subject: fixed glitch in unminimizing --- .../views/nodes/CollectionFreeFormDocumentView.tsx | 51 ++++++++++------------ 1 file changed, 24 insertions(+), 27 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 03538ae66..b82d02af5 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -20,7 +20,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { const schema = createSchema({ zoomBasis: "number", - zIndex: "number" + zIndex: "number", }); //TODO Types: The import order is wrong, so positionSchema is undefined @@ -43,9 +43,8 @@ export class CollectionFreeFormDocumentView extends DocComponent this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; panelWidth = () => this.props.PanelWidth(); panelHeight = () => this.props.PanelHeight(); @@ -87,8 +82,8 @@ export class CollectionFreeFormDocumentView extends DocComponent { let now = Date.now(); let progress = Math.min(1, (now - stime) / 200); let pval = maximizing ? [icon[0] + (targ[0] - icon[0]) * progress, icon[1] + (targ[1] - icon[1]) * progress] : [targ[0] + (icon[0] - targ[0]) * progress, targ[1] + (icon[1] - targ[1]) * progress]; - target.width = maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress; - target.height = maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress; - target.x = pval[0]; - target.y = pval[1]; + this.props.Document.width = maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress; + this.props.Document.height = maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress; + this.props.Document.x = pval[0]; + this.props.Document.y = pval[1]; + if (first) { + this.props.Document.proto!.willMaximize = false; + } if (now < stime + 200) { - this.animateBetweenIcon(false, icon, targ, width, height, stime, target, maximizing); + this.animateBetweenIcon(false, icon, targ, width, height, stime, maximizing); } else { if (!maximizing) { - target.proto!.isMinimized = true; - target.x = targ[0]; - target.y = targ[1]; - target.width = width; - target.height = height; + this.props.Document.proto!.isMinimized = true; + this.props.Document.x = targ[0]; + this.props.Document.y = targ[1]; + this.props.Document.width = width; + this.props.Document.height = height; } - target.proto!.isIconAnimating = undefined; + this.props.Document.proto!.isIconAnimating = undefined; } }, 2); @@ -151,7 +147,8 @@ export class CollectionFreeFormDocumentView extends DocComponent([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]) } } @@ -263,7 +260,7 @@ export class CollectionFreeFormDocumentView extends DocComponent {this.docView} -- cgit v1.2.3-70-g09d2 From 5c7926ebe144644814043c43c0cdc2cf8866e4cd Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 16 May 2019 11:36:15 -0400 Subject: fixed highlighting thickness as much as possible. seems to be a minimum width of around 0.1 which is a problem zooming in. --- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index b82d02af5..7c7ca9e25 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -247,11 +247,11 @@ export class CollectionFreeFormDocumentView extends DocComponent Date: Thu, 16 May 2019 12:28:31 -0400 Subject: fixed MakeAlias to check if doc is prototype. fixed summary template to bottom/right + capture image when zoomed, fixed full screen to copy view data on delegate --- src/client/views/Templates.tsx | 2 +- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/new_fields/Doc.ts | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 8d6bfbefd..5d29e68ae 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -74,7 +74,7 @@ export namespace Templates { export function ImageOverlay(width: number, height: number, field: string = "thumbnail") { return (`
{layout}
-
+
`); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 17d0a533e..12edb2c2a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -257,7 +257,7 @@ export class MarqueeView extends React.Component if (e.key === "s" || e.key === "p") { - htmlToImage.toPng(this._mainCont.current!, { width: bounds.width, height: bounds.height, quality: 1 }).then((dataUrl) => { + htmlToImage.toPng(this._mainCont.current!, { width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, quality: 1 }).then((dataUrl) => { selected.map(d => { this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 260630216..cf8bcbb42 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -227,7 +227,7 @@ export class DocumentView extends DocComponent(Docu } } fullScreenClicked = (e: React.MouseEvent): void => { - const doc = Doc.MakeDelegate(FieldValue(this.Document.proto)); + const doc = Doc.MakeCopy(this.props.Document, false); if (doc) { CollectionDockingView.Instance.OpenFullScreen(doc); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 2ae816da4..de72be3ea 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -140,7 +140,7 @@ export namespace Doc { return Cast(Get(doc, key, ignoreProto), ctor) as FieldResult; } export async function SetOnPrototype(doc: Doc, key: string, value: Field) { - const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") == -1 ? doc.proto : doc; + const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : doc; if (proto) { proto[key] = value; @@ -178,9 +178,10 @@ export namespace Doc { } export function MakeAlias(doc: Doc) { + const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : undefined; const alias = new Doc; - if (!doc.proto) { + if (!proto) { alias.proto = doc; } else { PromiseValue(Cast(doc.proto, Doc)).then(proto => { -- cgit v1.2.3-70-g09d2 From 171f285b5e61d7a0591578f1499f81b779a3c340 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 16 May 2019 15:54:34 -0400 Subject: fixed ? pdf rendering. freezing text boxes. --- src/client/views/nodes/FormattedTextBox.tsx | 12 ++++++------ src/client/views/nodes/PDFBox.tsx | 25 +++++++++++++++---------- 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 8e04071c7..f24d4ae88 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -269,14 +269,14 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } //REPLACE THIS WITH CAPABILITIES SPECIFIC TO THIS TYPE OF NODE - textCapability = (e: React.MouseEvent): void => { + freezeNativeDimensions = (e: React.MouseEvent): void => { if (NumCast(this.props.Document.nativeWidth)) { - this.props.Document.nativeWidth = undefined; - this.props.Document.nativeHeight = undefined; + this.props.Document.proto!.nativeWidth = undefined; + this.props.Document.proto!.nativeHeight = undefined; } else { - this.props.Document.nativeWidth = this.props.Document[WidthSym](); - this.props.Document.nativeHeight = this.props.Document[HeightSym](); + this.props.Document.proto!.nativeWidth = this.props.Document[WidthSym](); + this.props.Document.proto!.nativeHeight = this.props.Document[HeightSym](); } } specificContextMenu = (e: React.MouseEvent): void => { @@ -286,7 +286,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } ContextMenu.Instance.addItem({ description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", - event: this.textCapability + event: this.freezeNativeDimensions }); } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 14fe2df80..f6328fa83 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -71,13 +71,14 @@ export class PDFBox extends DocComponent(PdfDocumen @computed private get thumbnailPage() { return NumCast(this.props.Document.thumbnailPage, -1); } componentDidMount() { + let wasSelected = false; this._reactionDisposer = reaction( - () => [SelectionManager.SelectedDocuments().slice()], + () => this.props.isSelected(), () => { - if (this.curPage > 0 && this.thumbnailPage > 0 && this.curPage !== this.thumbnailPage && !this.props.isSelected()) { + if (this.curPage > 0 && this.curPage !== this.thumbnailPage && wasSelected && !this.props.isSelected()) { this.saveThumbnail(); - this._interactive = true; } + wasSelected = this._interactive = this.props.isSelected(); }, { fireImmediately: true }); @@ -256,7 +257,7 @@ export class PDFBox extends DocComponent(PdfDocumen .catch(function (error: any) { console.error('oops, something went wrong!', error); }); - }, 250); + }, 1250); } @action @@ -283,24 +284,27 @@ export class PDFBox extends DocComponent(PdfDocumen } @computed get pdfPage() { - return ; + console.log(this.curPage); + return ; } @computed get pdfContent() { + trace(); let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField); if (!pdfUrl) { return

No pdf url to render

; } - let body = NumCast(this.props.Document.nativeHeight) ? - this.pdfPage : + let pdfpage = this.pdfPage; + let body = this.Document.nativeHeight ? + pdfpage : {({ measureRef }) =>
- {this.pdfPage} + {pdfpage}
}
; - let xf = NumCast(this.Document.nativeHeight) / this.renderHeight; + let xf = (this.Document.nativeHeight || 0) / this.renderHeight; return
{body} @@ -336,7 +340,8 @@ export class PDFBox extends DocComponent(PdfDocumen @action onKeyDown = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = true); @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false); render() { - let classname = "pdfBox-cont"; // + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); + trace(); + let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); return (
{this.pdfRenderer} -- cgit v1.2.3-70-g09d2 From b29a0d1cef60b55f609fcd94ad38232ae557e681 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 16 May 2019 18:32:57 -0400 Subject: Fixed linter errors --- src/client/goldenLayout.d.ts | 3 +++ src/client/northstar/dash-fields/HistogramField.ts | 2 +- src/client/northstar/model/ModelHelpers.ts | 9 +++---- src/client/util/DragManager.ts | 2 +- src/client/util/RichTextSchema.tsx | 16 +++++------ src/client/util/TooltipTextMenu.tsx | 13 ++++----- src/client/views/DocumentDecorations.tsx | 31 +++++++++++----------- src/client/views/PresentationView.tsx | 4 +-- src/client/views/TemplateMenu.tsx | 4 +-- .../views/collections/CollectionDockingView.tsx | 5 ++-- .../views/collections/CollectionSchemaView.tsx | 10 +++---- .../views/collections/CollectionTreeView.tsx | 9 ++++--- .../collections/collectionFreeForm/MarqueeView.tsx | 13 ++++----- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 8 +++--- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 3 ++- src/client/views/nodes/VideoBox.tsx | 22 +++++++-------- src/new_fields/CursorField.ts | 6 ++--- src/new_fields/Doc.ts | 4 +-- src/new_fields/ObjectField.ts | 2 +- .../authentication/models/current_user_utils.ts | 2 +- 24 files changed, 91 insertions(+), 85 deletions(-) create mode 100644 src/client/goldenLayout.d.ts (limited to 'src/client/views/nodes') diff --git a/src/client/goldenLayout.d.ts b/src/client/goldenLayout.d.ts new file mode 100644 index 000000000..b50240563 --- /dev/null +++ b/src/client/goldenLayout.d.ts @@ -0,0 +1,3 @@ + +declare const GoldenLayout: any; +export = GoldenLayout; \ No newline at end of file diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index aabc77bb2..1ee2189b9 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -52,7 +52,7 @@ export class HistogramField extends ObjectField { [Copy]() { let y = this.HistoOp; - let z = this.HistoOp["Copy"]; + let z = this.HistoOp.Copy; return new HistogramField(HistogramOperation.Duplicate(this.HistoOp)); } } \ No newline at end of file diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts index 80bb71224..88e6e72b8 100644 --- a/src/client/northstar/model/ModelHelpers.ts +++ b/src/client/northstar/model/ModelHelpers.ts @@ -32,12 +32,9 @@ export class ModelHelpers { public static GetAggregateParametersIndex(histogramResult: HistogramResult, aggParameters?: AggregateParameters): number { return Array.from(histogramResult.aggregateParameters!).findIndex((value, i, set) => { - if (set[i] instanceof CountAggregateParameters && value instanceof CountAggregateParameters) - return true; - if (set[i] instanceof MarginAggregateParameters && value instanceof MarginAggregateParameters) - return true; - if (set[i] instanceof SumAggregateParameters && value instanceof SumAggregateParameters) - return true; + if (set[i] instanceof CountAggregateParameters && value instanceof CountAggregateParameters) return true; + if (set[i] instanceof MarginAggregateParameters && value instanceof MarginAggregateParameters) return true; + if (set[i] instanceof SumAggregateParameters && value instanceof SumAggregateParameters) return true; return false; }); } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 26da34e67..05eb5c38a 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -41,7 +41,7 @@ export function SetupDrag(_reference: React.RefObject, docFunc: () export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Doc) { let srcTarg = sourceDoc.proto; let draggedDocs: Doc[] = []; - let draggedFromDocs: Doc[] = [] + let draggedFromDocs: Doc[] = []; if (srcTarg) { let linkToDocs = await DocListCastAsync(srcTarg.linkedToDocs); let linkFromDocs = await DocListCastAsync(srcTarg.linkedFromDocs); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index c0e6f7899..3e3e98206 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -97,13 +97,13 @@ export const nodes: { [index: string]: NodeSpec } = { title: dom.getAttribute("title"), alt: dom.getAttribute("alt"), width: Math.min(100, Number(dom.getAttribute("width"))), - } + }; } }], // TODO if we don't define toDom, something weird happens: dragging the image will not move it but clone it. Why? toDOM(node) { - const attrs = { style: `width: ${node.attrs.width}` } - return ["img", { ...node.attrs, ...attrs }] + const attrs = { style: `width: ${node.attrs.width}` }; + return ["img", { ...node.attrs, ...attrs }]; } }, @@ -375,7 +375,7 @@ export class ImageResizeView { const currentX = e.pageX; const diffInPx = currentX - startX; self._outer.style.width = `${startWidth + diffInPx}`; - } + }; const onpointerup = () => { document.removeEventListener("pointermove", onpointermove); @@ -384,11 +384,11 @@ export class ImageResizeView { view.state.tr.setNodeMarkup(getPos(), null, { src: node.attrs.src, width: self._outer.style.width }) .setSelection(view.state.selection)); - } + }; - document.addEventListener("pointermove", onpointermove) - document.addEventListener("pointerup", onpointerup) - } + document.addEventListener("pointermove", onpointermove); + document.addEventListener("pointerup", onpointerup); + }; this._outer.appendChild(this._handle); this._outer.appendChild(this._img); diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 6eb654319..223921428 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -175,7 +175,7 @@ export class TooltipTextMenu { this.linkText.style.width = "150px"; this.linkText.style.overflow = "hidden"; this.linkText.style.color = "white"; - this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); } + this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); }; let linkBtn = document.createElement("div"); linkBtn.textContent = ">>"; linkBtn.style.width = "20px"; @@ -192,8 +192,9 @@ export class TooltipTextMenu { let docid = href.replace(DocServer.prepend("/doc/"), ""); DocServer.GetRefField(docid).then(action((f: Opt) => { if (f instanceof Doc) { - if (DocumentManager.Instance.getDocumentView(f)) + if (DocumentManager.Instance.getDocumentView(f)) { DocumentManager.Instance.getDocumentView(f)!.props.focus(f); + } else CollectionDockingView.Instance.AddRightSplit(f); } })); @@ -201,7 +202,7 @@ export class TooltipTextMenu { e.stopPropagation(); e.preventDefault(); } - } + }; this.linkDrag = document.createElement("img"); this.linkDrag.src = "https://seogurusnyc.com/wp-content/uploads/2016/12/link-1.png"; this.linkDrag.style.width = "20px"; @@ -216,12 +217,12 @@ export class TooltipTextMenu { { handlers: { dragComplete: action(() => { - let m = dragData.droppedDocuments as Doc[]; + let m = dragData.droppedDocuments; this.makeLink(DocServer.prepend("/doc/" + m[0][Id])); }), }, hideSource: false - }) + }); }; this.linkEditor.appendChild(this.linkDrag); this.linkEditor.appendChild(this.linkText); @@ -239,7 +240,7 @@ export class TooltipTextMenu { e.stopPropagation(); e.preventDefault(); } - } + }; this.tooltip.appendChild(this.linkEditor); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index b2c65a31f..7083b1003 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -250,22 +250,21 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> selectedDocs[0].props.removeDocument && selectedDocs[0].props.removeDocument(this._iconDoc); } if (!this._removeIcon) { - if (selectedDocs.length === 1) + if (selectedDocs.length === 1) { this.getIconDoc(selectedDocs[0]).then(icon => selectedDocs[0].props.toggleMinimized()); - else - if (Math.abs(e.pageX - this._downX) < Utils.DRAG_THRESHOLD && - Math.abs(e.pageY - this._downY) < Utils.DRAG_THRESHOLD) { - let docViews = SelectionManager.ViewsSortedVertically(); - let topDocView = docViews[0]; - let ind = topDocView.templates.indexOf(Templates.Bullet.Layout); - if (ind !== -1) { - topDocView.templates.splice(ind, 1); - topDocView.props.Document.subBulletDocs = undefined; - } else { - topDocView.addTemplate(Templates.Bullet); - topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); - } + } else if (Math.abs(e.pageX - this._downX) < Utils.DRAG_THRESHOLD && + Math.abs(e.pageY - this._downY) < Utils.DRAG_THRESHOLD) { + let docViews = SelectionManager.ViewsSortedVertically(); + let topDocView = docViews[0]; + let ind = topDocView.templates.indexOf(Templates.Bullet.Layout); + if (ind !== -1) { + topDocView.templates.splice(ind, 1); + topDocView.props.Document.subBulletDocs = undefined; + } else { + topDocView.addTemplate(Templates.Bullet); + topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); } + } } this._removeIcon = false; } @@ -537,9 +536,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (temp !== Templates.Bullet.Layout || i === 0) { res.push(temp); } - }) + }); } - return res + return res; }, [] as string[]); let checked = false; docTemps.forEach(temp => { diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index 098e725c7..7d0dc2913 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react"; -import React = require("react") +import React = require("react"); import { observable, action, runInAction, reaction } from "mobx"; -import "./PresentationView.scss" +import "./PresentationView.scss"; import "./Main.tsx"; import { DocumentManager } from "../util/DocumentManager"; import { Utils } from "../../Utils"; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index cfe1b0663..e5b679e24 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -43,7 +43,7 @@ export class TemplateMenu extends React.Component { @action toggleTemplate = (event: React.ChangeEvent, template: Template): void => { if (event.target.checked) { - if (template.Name == "Bullet") { + if (template.Name === "Bullet") { let topDocView = this.props.docs[0]; topDocView.addTemplate(template); topDocView.props.Document.subBulletDocs = new List(this.props.docs.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); @@ -52,7 +52,7 @@ export class TemplateMenu extends React.Component { } this.props.templates.set(template, true); } else { - if (template.Name == "Bullet") { + if (template.Name === "Bullet") { let topDocView = this.props.docs[0]; topDocView.removeTemplate(template); topDocView.props.Document.subBulletDocs = undefined; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 58f1e33a1..deec64225 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -83,7 +83,7 @@ export class CollectionDockingView extends React.Component tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => { if (Doc.AreProtosEqual(DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)!.Document, document)) { child.contentItems[j].remove(); @@ -94,8 +94,9 @@ export class CollectionDockingView extends React.Component doc) { let fieldContentView = ; let reference = React.createRef(); let onItemDown = (e: React.PointerEvent) => - (this.props.CollectionView!.props.isSelected() ? + (this.props.CollectionView.props.isSelected() ? SetupDrag(reference, () => props.Document, this.props.moveDocument)(e) : undefined); let applyToDoc = (doc: Doc, run: (args?: { [name: string]: any }) => any) => { const res = run({ this: doc }); @@ -127,7 +127,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } const run = script.run; //TODO This should be able to be refactored to compile the script once - const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]) + const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]); val && val.forEach(doc => applyToDoc(doc, run)); }}> @@ -230,14 +230,14 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { DocListCast(this.props.Document.data).map(doc => { csv += self.columns.reduce((val, col) => val + (doc[col] ? doc[col]!.toString() : "") + ",", ""); csv = csv.substr(0, csv.length - 1) + "\n"; - }) + }); csv.substring(0, csv.length - 1); let dbName = StrCast(this.props.Document.title); let res = await Gateway.Instance.PostSchema(csv, dbName); if (self.props.CollectionView.props.addDocument) { let schemaDoc = await Docs.DBDocument("https://www.cs.brown.edu/" + dbName, { title: dbName }); if (schemaDoc) { - self.props.CollectionView.props.addDocument(schemaDoc, false); + self.props.CollectionView.props.addDocument(schemaDoc, false); } } } @@ -263,7 +263,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { get previewDocument(): Doc | undefined { const children = DocListCast(this.props.Document[this.props.fieldKey]); const selected = children.length > this._selectedIndex ? FieldValue(children[this._selectedIndex]) : undefined; - return selected ? (this.previewScript && this.previewScript != "this" ? FieldValue(Cast(selected[this.previewScript], Doc)) : selected) : undefined; + return selected ? (this.previewScript && this.previewScript !== "this" ? FieldValue(Cast(selected[this.previewScript], Doc)) : selected) : undefined; } get tableWidth() { return (this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH) * (1 - this.splitPercentage / 100); } get previewRegionHeight() { return this.props.PanelHeight() - 2 * this.borderWidth; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 70c09d97c..6acef434e 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -56,7 +56,7 @@ class TreeView extends React.Component { } else { CollectionDockingView.Instance.AddRightSplit(this.props.document); } - }; + } get children() { return Cast(this.props.document.data, listSpec(Doc), []); // bcz: needed? .filter(doc => FieldValue(doc)); @@ -184,8 +184,9 @@ class TreeView extends React.Component { {TreeView.GetChildElements(doc instanceof Doc ? [doc] : docList, key !== "data", (doc: Doc) => this.remove(doc, key), this.move, this.props.dropAction)}
); - } else + } else { bulletType = BulletType.Collapsed; + } } }); return
{
; } public static GetChildElements(docs: Doc[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { - return docs.filter(child => child instanceof Doc && !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).filter(doc => FieldValue(doc)).map(child => - ); + return docs.filter(child => !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).map(child => + ); } } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 12edb2c2a..c3c4115b8 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -63,7 +63,7 @@ export class MarqueeView extends React.Component e.preventDefault(); (async () => { let text: string = await navigator.clipboard.readText(); - let ns = text.split("\n").filter(t => t.trim() != "\r" && t.trim() != ""); + let ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); for (let i = 0; i < ns.length - 1; i++) { while (!(ns[i].trim() === "" || ns[i].endsWith("-\r") || ns[i].endsWith("-") || ns[i].endsWith(";\r") || ns[i].endsWith(";") || @@ -80,7 +80,7 @@ export class MarqueeView extends React.Component let newBox = Docs.TextDocument({ width: 200, height: 35, x: x + indent / 3 * 10, y: y, documentText: "@@@" + line, title: line }); this.props.addDocument(newBox, false); y += 40 * this.props.getTransform().Scale; - }) + }); })(); } else if (e.key === "b" && e.ctrlKey) { //heuristically converts pasted text into a table. @@ -93,9 +93,10 @@ export class MarqueeView extends React.Component e.preventDefault(); (async () => { let text: string = await navigator.clipboard.readText(); - let ns = text.split("\n").filter(t => t.trim() != "\r" && t.trim() != ""); - while (ns.length > 0 && ns[0].split("\t").length < 2) + let ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); + while (ns.length > 0 && ns[0].split("\t").length < 2) { ns.splice(0, 1); + } if (ns.length > 0) { let columns = ns[0].split("\t"); let docList: Doc[] = []; @@ -109,7 +110,7 @@ export class MarqueeView extends React.Component let doc = new Doc(); columns.forEach((col, i) => doc[columns[i]] = (values.length > i ? ((values[i].indexOf(Number(values[i]).toString()) !== -1) ? Number(values[i]) : values[i]) : undefined)); if (groupAttr) { - doc["_group"] = groupAttr; + doc._group = groupAttr; } doc.title = i.toString(); docList.push(doc); @@ -284,7 +285,7 @@ export class MarqueeView extends React.Component // summarizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]); // }); this.props.addLiveTextDocument(summary); - }) + }); } else { this.props.addDocument(newCollection, false); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 7c7ca9e25..d4f660b3f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -149,7 +149,7 @@ export class CollectionFreeFormDocumentView extends DocComponent([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]) + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]); } } }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cf8bcbb42..428dd9b36 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -244,7 +244,7 @@ export class DocumentView extends DocComponent(Docu const protoDest = destDoc.proto; const protoSrc = sourceDoc.proto; - if (de.mods == "Control") { + if (de.mods === "Control") { let src = protoSrc ? protoSrc : sourceDoc; let dst = protoDest ? protoDest : destDoc; dst.data = src; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f24d4ae88..f30022508 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -184,7 +184,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), dispatchTransaction: this.dispatchTransaction, nodeViews: { - image(node, view, getPos) { return new ImageResizeView(node, view, getPos) } + image(node, view, getPos) { return new ImageResizeView(node, view, getPos); } } }); let text = StrCast(this.props.Document.documentText); @@ -232,9 +232,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let docid = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; DocServer.GetRefField(docid).then(action((f: Opt) => { if (f instanceof Doc) { - if (DocumentManager.Instance.getDocumentView(f)) + if (DocumentManager.Instance.getDocumentView(f)) { DocumentManager.Instance.getDocumentView(f)!.props.focus(f); - else CollectionDockingView.Instance.AddRightSplit(f); + } else { + CollectionDockingView.Instance.AddRightSplit(f); + } } })); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 6472ae711..3cc60a6c5 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -165,7 +165,7 @@ export class ImageBox extends DocComponent(ImageD else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => (p as ImageField).url.href); let nativeWidth = FieldValue(this.Document.nativeWidth, (this.props.PanelWidth as any) as string ? Number((this.props.PanelWidth as any) as string) : 50); let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; - let id = this.props.id; // bcz: used to set id = "isExpander" in templates.tsx + let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx return (
{ @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); } - get fieldDocToLayout() { return this.props.fieldKey ? FieldValue(Cast(this.props.Document[this.props.fieldKey], Doc)) : this.props.Document } + get fieldDocToLayout() { return this.props.fieldKey ? FieldValue(Cast(this.props.Document[this.props.fieldKey], Doc)) : this.props.Document; } constructor(props: FieldViewProps) { super(props); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 5de660d57..4f7919f50 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -46,8 +46,9 @@ export class KeyValuePair extends React.Component {
, + ,
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d4f660b3f..001ce3095 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -205,11 +205,12 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.Document; - const protoDest = destDoc.proto; - const protoSrc = sourceDoc.proto; - if (de.mods === "Control") { + if (de.mods === "AltKey") { + const protoDest = destDoc.proto; + const protoSrc = sourceDoc.proto; let src = protoSrc ? protoSrc : sourceDoc; let dst = protoDest ? protoDest : destDoc; - dst.data = src; + dst.data = (src.data! as ObjectField)[Copy](); dst.nativeWidth = src.nativeWidth; dst.nativeHeight = src.nativeHeight; } else { - Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); + Doc.MakeLink(sourceDoc, destDoc); de.data.droppedDocuments.push(destDoc); } e.stopPropagation(); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f30022508..bf98fb40b 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -111,9 +111,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.Document; - const protoDest = destDoc.proto; - const protoSrc = sourceDoc.proto; - Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); + Doc.MakeLink(sourceDoc, destDoc); de.data.droppedDocuments.push(destDoc); e.stopPropagation(); } diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 611cb66b6..68b692aad 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -31,7 +31,7 @@ export class LinkBox extends React.Component { @undoBatch onViewButtonPressed = async (e: React.PointerEvent): Promise => { e.stopPropagation(); - DocumentManager.Instance.jumpToDocument(this.props.pairedDoc); + DocumentManager.Instance.jumpToDocument(this.props.pairedDoc, e.altKey); } onEditButtonPressed = (e: React.PointerEvent): void => { diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 11117122d..4cf798249 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -6,8 +6,7 @@ import { LinkEditor } from "./LinkEditor"; import './LinkMenu.scss'; import React = require("react"); import { Doc, DocListCast } from "../../../new_fields/Doc"; -import { Cast, FieldValue } from "../../../new_fields/Types"; -import { listSpec } from "../../../new_fields/Schema"; +import { Cast, FieldValue, StrCast } from "../../../new_fields/Types"; import { Id } from "../../../new_fields/RefField"; interface Props { @@ -24,7 +23,7 @@ export class LinkMenu extends React.Component { return links.map(link => { let doc = FieldValue(Cast(link[key], Doc)); if (doc) { - return this._editingLink = link)} type={type} />; + return this._editingLink = link)} type={type} />; } }); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index c898f697b..ad3b880cd 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -216,6 +216,8 @@ export namespace Doc { } export function MakeLink(source: Doc, target: Doc) { + let protoSrc = source.proto ? source.proto : source; + let protoTarg = target.proto ? target.proto : target; UndoManager.RunInBatch(() => { let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 }); //let linkDoc = new Doc; @@ -226,15 +228,15 @@ export namespace Doc { linkDoc.proto!.linkedTo = target; linkDoc.proto!.linkedFrom = source; - let linkedFrom = Cast(target.linkedFromDocs, listSpec(Doc)); + let linkedFrom = Cast(protoTarg.linkedFromDocs, listSpec(Doc)); if (!linkedFrom) { - target.linkedFromDocs = linkedFrom = new List(); + protoTarg.linkedFromDocs = linkedFrom = new List(); } linkedFrom.push(linkDoc); - let linkedTo = Cast(source.linkedToDocs, listSpec(Doc)); + let linkedTo = Cast(protoSrc.linkedToDocs, listSpec(Doc)); if (!linkedTo) { - source.linkedToDocs = linkedTo = new List(); + protoSrc.linkedToDocs = linkedTo = new List(); } linkedTo.push(linkDoc); return linkDoc; -- cgit v1.2.3-70-g09d2 From 2c8aaae6f026199e3675f5e7b4677724d5089ae7 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 17 May 2019 14:53:09 -0400 Subject: added something to follow links in current tab ? --- src/client/util/DocumentManager.ts | 33 +++++++++++++--------- .../views/collections/CollectionSchemaView.tsx | 7 ----- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- 3 files changed, 20 insertions(+), 22 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index c6962ad8d..d06af6dd5 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,11 +1,14 @@ import { computed, observable } from 'mobx'; import { DocumentView } from '../views/nodes/DocumentView'; -import { Doc, DocListCast } from '../../new_fields/Doc'; +import { Doc, DocListCast, Opt } from '../../new_fields/Doc'; import { FieldValue, Cast, NumCast, BoolCast } from '../../new_fields/Types'; import { listSpec } from '../../new_fields/Schema'; import { undoBatch } from './UndoManager'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { Id } from '../../new_fields/RefField'; +import { CollectionView } from '../views/collections/CollectionView'; +import { CollectionPDFView } from '../views/collections/CollectionPDFView'; +import { CollectionVideoView } from '../views/collections/CollectionVideoView'; export class DocumentManager { @@ -27,31 +30,33 @@ export class DocumentManager { // this.DocumentViews = new Array(); } - public getDocumentViewById(id: string): DocumentView | null { + public getDocumentViewById(id: string, preferredCollection?: CollectionView | CollectionPDFView | CollectionVideoView): DocumentView | null { let toReturn: DocumentView | null = null; + let passes = preferredCollection ? [preferredCollection, undefined] : [undefined]; - //gets document view that is in a freeform canvas collection - DocumentManager.Instance.DocumentViews.map(view => { - if (view.props.Document[Id] === id) { - toReturn = view; - return; - } - }); - if (!toReturn) { + for (let i = 0; i < passes.length; i++) { DocumentManager.Instance.DocumentViews.map(view => { - let doc = view.props.Document.proto; - if (doc && doc[Id] === id) { + if (view.props.Document[Id] === id && (!passes[i] || view.props.ContainingCollectionView === preferredCollection)) { toReturn = view; + return; } }); + if (!toReturn) { + DocumentManager.Instance.DocumentViews.map(view => { + let doc = view.props.Document.proto; + if (doc && doc[Id] === id && (!passes[i] || view.props.ContainingCollectionView === preferredCollection)) { + toReturn = view; + } + }); + } } return toReturn; } - public getDocumentView(toFind: Doc): DocumentView | null { - return this.getDocumentViewById(toFind[Id]); + public getDocumentView(toFind: Doc, preferredCollection?: CollectionView | CollectionPDFView | CollectionVideoView): DocumentView | null { + return this.getDocumentViewById(toFind[Id], preferredCollection); } public getDocumentViews(toFind: Doc): DocumentView[] { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 497dfde88..e2b90e26d 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -24,14 +24,7 @@ import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; import { Id } from "../../../new_fields/RefField"; -import { isUndefined } from "typescript-collections/dist/lib/util"; -import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { Gateway } from "../../northstar/manager/Gateway"; -import { DocServer } from "../../DocServer"; -import { ColumnAttributeModel } from "../../northstar/core/attribute/AttributeModel"; -import { HistogramOperation } from "../../northstar/operations/HistogramOperation"; -import { AggregateFunction } from "../../northstar/model/idea/idea"; -import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel"; import { Docs } from "../../documents/Documents"; import { ContextMenu } from "../ContextMenu"; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 001ce3095..00aa71656 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -187,7 +187,7 @@ export class CollectionFreeFormDocumentView extends DocComponent Date: Fri, 17 May 2019 19:50:32 -0400 Subject: added right-click "open Tab" and double-click open tab --- src/client/views/Main.tsx | 1 + .../views/collections/CollectionDockingView.tsx | 20 ++++++++++++++++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 19 +++++++++++++++++++ src/client/views/nodes/DocumentView.tsx | 2 ++ src/client/views/nodes/FieldView.tsx | 2 ++ src/client/views/nodes/ImageBox.tsx | 4 +++- 7 files changed, 46 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 51ad0aa49..177047a9a 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -166,6 +166,7 @@ export class Main extends React.Component { { @observable private _panelWidth = 0; @observable private _panelHeight = 0; @observable private _document: Opt; - + _stack: any; constructor(props: any) { super(props); + this._stack = (this.props as any).glContainer.parent.parent; DocServer.GetRefField(this.props.documentId).then(action((f: Opt) => this._document = f as Doc)); } @@ -420,6 +432,9 @@ export class DockedFrameRenderer extends React.Component { } get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } + addDocTab = (doc: Doc) => { + CollectionDockingView.Instance.AddTab(this._stack, doc); + } get content() { if (!this._document) { return (null); @@ -441,6 +456,7 @@ export class DockedFrameRenderer extends React.Component { parentActive={returnTrue} whenActiveChanged={emptyFunction} focus={emptyFunction} + addDocTab={this.addDocTab} ContainingCollectionView={undefined} />
); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6e4c79e62..ad32f70dc 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -300,6 +300,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { parentActive: this.props.active, whenActiveChanged: this.props.whenActiveChanged, bringToFront: this.bringToFront, + addDocTab: this.props.addDocTab, }; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 00aa71656..a0efc3154 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -159,6 +159,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { this._downX = e.clientX; @@ -166,6 +167,24 @@ export class CollectionFreeFormDocumentView extends DocComponent { + + document.removeEventListener("pointerup", this.onPointerUp); + if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { + this.props.addDocTab(this.props.Document); + } + e.stopPropagation(); } onClick = async (e: React.MouseEvent) => { e.stopPropagation(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5264773b0..9a5d21b49 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -57,6 +57,7 @@ export interface DocumentViewProps { whenActiveChanged: (isActive: boolean) => void; toggleMinimized: () => void; bringToFront: (doc: Doc) => void; + addDocTab: (doc: Doc) => void; } const schema = createSchema({ @@ -307,6 +308,7 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeButton }); cm.addItem({ description: "Fields", event: this.fieldsClicked }); cm.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) }); + cm.addItem({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document) }); cm.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) }); cm.addItem({ description: "Find aliases", event: async () => { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 34b6c5e70..b5dfd18eb 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -35,6 +35,7 @@ export interface FieldViewProps { isTopMost: boolean; selectOnLoad: boolean; addDocument?: (document: Doc, allowDuplicates?: boolean) => boolean; + addDocTab: (document: Doc) => boolean; removeDocument?: (document: Doc) => boolean; moveDocument?: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; ScreenToLocalTransform: () => Transform; @@ -87,6 +88,7 @@ export class FieldView extends React.Component { return ( (ImageD let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx return ( -
+
Date: Fri, 17 May 2019 22:35:43 -0400 Subject: fixed shift-drag of main collection. --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ad32f70dc..b44a2f527 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -116,7 +116,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) || (e.button === 0 && e.altKey)) && this.props.active())) || (!CollectionFreeFormView.RIGHT_BTN_DRAG && - ((e.button === 0 && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) && this.props.active()))) { + ((e.button === 0 && !e.shiftKey && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) && this.props.active()))) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9a5d21b49..b7d8eda9c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -181,11 +181,7 @@ export class DocumentView extends DocComponent(Docu } this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0; if (e.shiftKey && e.buttons === 1) { - if (this.props.isTopMost) { - this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey ? "alias" : undefined, this._hitExpander); - } else if (this.props.Document) { - CollectionDockingView.Instance.StartOtherDrag([Doc.MakeAlias(this.props.Document)], e); - } + CollectionDockingView.Instance.StartOtherDrag([Doc.MakeAlias(this.props.Document)], e); e.stopPropagation(); } else if (this.active) { //e.stopPropagation(); // bcz: doing this will block click events from CollectionFreeFormDocumentView which are needed for iconifying,etc -- cgit v1.2.3-70-g09d2 From 4d6e5c21c452d4a9423f7925f6117b4f6d97093b Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 18 May 2019 00:27:32 -0400 Subject: removed some prints --- src/client/views/nodes/ImageBox.tsx | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 3cc60a6c5..881c4553a 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -42,7 +42,6 @@ export class ImageBox extends DocComponent(ImageD onLoad = (target: any) => { var h = this._imgRef.current!.naturalHeight; var w = this._imgRef.current!.naturalWidth; - console.log("title: " + this.Document.title); if (this._photoIndex === 0) { Doc.SetOnPrototype(this.Document, "nativeHeight", FieldValue(this.Document.nativeWidth, 0) * h / w); this.Document.height = FieldValue(this.Document.width, 0) * h / w; @@ -158,7 +157,6 @@ export class ImageBox extends DocComponent(ImageD } render() { - trace(); let field = this.Document[this.props.fieldKey]; let paths: string[] = ["http://www.cs.brown.edu/~bcz/face.gif"]; if (field instanceof ImageField) paths = [field.url.href]; -- cgit v1.2.3-70-g09d2 From 718269e2fa50e20227bfbb32b1a1b6ec8f78184d Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 18 May 2019 09:42:43 -0400 Subject: fixed font error message. Improved opening summaries as either inTab or inPlace and switching with the alt-key --- src/client/views/ContextMenu.tsx | 3 ++- src/client/views/DocumentDecorations.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 7 +++-- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 30 ++++++++++++---------- src/client/views/nodes/DocumentView.tsx | 4 +-- src/client/views/nodes/FieldView.tsx | 2 +- 7 files changed, 30 insertions(+), 22 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 9ccbb7149..9143c012e 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -5,9 +5,10 @@ import { observer } from "mobx-react" import "./ContextMenu.scss" import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faSearch } from '@fortawesome/free-solid-svg-icons'; +import { faSearch, faCircle } from '@fortawesome/free-solid-svg-icons'; library.add(faSearch); +library.add(faCircle); @observer export class ContextMenu extends React.Component { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 7083b1003..d440ed898 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -279,7 +279,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> iconDoc.proto!.title = selected.length > 1 ? "ICONset" : "ICON" + StrCast(doc.title); iconDoc.labelField = selected.length > 1 ? undefined : this._fieldKey; iconDoc.proto![this._fieldKey] = selected.length > 1 ? "collection" : undefined; - iconDoc.isMinimized = false; + iconDoc.proto!.isMinimized = false; iconDoc.width = Number(MINIMIZED_ICON_SIZE); iconDoc.height = Number(MINIMIZED_ICON_SIZE); iconDoc.x = NumCast(doc.x); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 28624e020..74f8ad242 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -432,8 +432,11 @@ export class DockedFrameRenderer extends React.Component { } get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } - addDocTab = (doc: Doc) => { - CollectionDockingView.Instance.AddTab(this._stack, doc); + addDocTab = (doc: Doc, location: string) => { + if (location === "onRight") + CollectionDockingView.Instance.AddRightSplit(doc); + else + CollectionDockingView.Instance.AddTab(this._stack, doc); } get content() { if (!this._document) { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index c3c4115b8..6301fd27e 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -272,9 +272,9 @@ export class MarqueeView extends React.Component newCollection.proto!.summaryDoc = summary; selected = [newCollection]; newCollection.x = bounds.left + bounds.width; - this.props.addDocument(newCollection, false); + //this.props.addDocument(newCollection, false); summary.proto!.summarizedDocs = new List(selected.map(s => s.proto!)); - //summary.proto!.maximizeOnRight = true; + summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight" //summary.proto!.isButton = true; //let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); // selected.map(summarizedDoc => { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index a0efc3154..833947ac3 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema"; -import { BoolCast, Cast, FieldValue, NumCast } from "../../../new_fields/Types"; +import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { OmitKeys, Utils } from "../../../Utils"; import { DocumentManager } from "../../util/DocumentManager"; import { SelectionManager } from "../../util/SelectionManager"; @@ -139,7 +139,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { let iconAnimating = Cast(maximizedDoc.isIconAnimating, List); - if (!iconAnimating || (Date.now() - iconAnimating[6] > 1000)) { + if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) { if (isMinimized === undefined) { isMinimized = BoolCast(maximizedDoc.isMinimized, false); } @@ -179,10 +179,9 @@ export class CollectionFreeFormDocumentView extends DocComponent { - document.removeEventListener("pointerup", this.onPointerUp); if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { - this.props.addDocTab(this.props.Document); + this.props.addDocTab(this.props.Document, "inTab"); } e.stopPropagation(); } @@ -193,6 +192,7 @@ export class CollectionFreeFormDocumentView extends DocComponent maxDoc.isMinimized = false); + hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView); + maxLocation = this.props.Document.maximizeLocation = (maxLocation === "inPlace" ? "inTab" : "inPlace"); + if (!hasView && maxLocation === "inPlace") { + this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(Doc.MakeDelegate(maxDoc), false)); + expandedDocs.forEach(maxDoc => maxDoc.isMinimized = true); + } + } + if (!hasView && maxLocation !== "inPlace") { let dataDocs = DocListCast(CollectionDockingView.Instance.props.Document.data); if (dataDocs) { - SelectionManager.DeselectAll(); expandedDocs.forEach(maxDoc => { - maxDoc.isMinimized = false; if (!CollectionDockingView.Instance.CloseRightSplit(maxDoc)) { - CollectionDockingView.Instance.AddRightSplit(Doc.MakeDelegate(maxDoc)); + this.props.addDocTab(Doc.MakeDelegate(maxDoc), maxLocation); } }); } } else { - //if (altKey) this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(maxDoc, false)); this.toggleIcon(expandedDocs); } } else if (linkedToDocs.length || linkedFromDocs.length) { - SelectionManager.DeselectAll(); let linkedFwdDocs = [ linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : expandedDocs[0], linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : expandedDocs[0]]; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7167da93b..760e31b49 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -68,7 +68,7 @@ export interface DocumentViewProps { whenActiveChanged: (isActive: boolean) => void; toggleMinimized: () => void; bringToFront: (doc: Doc) => void; - addDocTab: (doc: Doc) => void; + addDocTab: (doc: Doc, where: string) => void; } const schema = createSchema({ @@ -315,7 +315,7 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeButton, icon: "expand-arrows-alt" }); cm.addItem({ description: "Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Center", event: () => this.props.focus(this.props.Document), icon: "align-center" }); - cm.addItem({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document), icon: "expand-arrows-alt" }); + cm.addItem({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "inTab"), icon: "expand-arrows-alt" }); cm.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document), icon: "caret-square-right" }); cm.addItem({ description: "Find aliases", event: async () => { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index b5dfd18eb..5c149af99 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -35,7 +35,7 @@ export interface FieldViewProps { isTopMost: boolean; selectOnLoad: boolean; addDocument?: (document: Doc, allowDuplicates?: boolean) => boolean; - addDocTab: (document: Doc) => boolean; + addDocTab: (document: Doc, where: string) => boolean; removeDocument?: (document: Doc) => boolean; moveDocument?: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; ScreenToLocalTransform: () => Transform; -- cgit v1.2.3-70-g09d2 From 3fd191a2d031e1a186a4eb2e009887399a4bc347 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 18 May 2019 10:50:28 -0400 Subject: more fixes to maximizing docs to default to showing the same prototype each time. --- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 35 ++++++++++++---------- src/new_fields/Doc.ts | 6 ++++ 3 files changed, 26 insertions(+), 17 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 6301fd27e..d102c8af2 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -273,7 +273,7 @@ export class MarqueeView extends React.Component selected = [newCollection]; newCollection.x = bounds.left + bounds.width; //this.props.addDocument(newCollection, false); - summary.proto!.summarizedDocs = new List(selected.map(s => s.proto!)); + summary.proto!.summarizedDocs = new List(selected); summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight" //summary.proto!.isButton = true; //let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 833947ac3..7cb4c1dfe 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -137,7 +137,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { + maximizedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => { let iconAnimating = Cast(maximizedDoc.isIconAnimating, List); if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) { if (isMinimized === undefined) { @@ -204,28 +204,31 @@ export class CollectionFreeFormDocumentView extends DocComponent Doc.GetProto(doc)) let maxLocation = StrCast(this.props.Document.maximizeLocation, "inPlace"); - if (!hasView && altKey) { - expandedDocs.forEach(maxDoc => maxDoc.isMinimized = false); - hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView); - maxLocation = this.props.Document.maximizeLocation = (maxLocation === "inPlace" ? "inTab" : "inPlace"); - if (!hasView && maxLocation === "inPlace") { - this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(Doc.MakeDelegate(maxDoc), false)); - expandedDocs.forEach(maxDoc => maxDoc.isMinimized = true); + let getDispDoc = (target: Doc) => Object.getOwnPropertyNames(target).indexOf("isPrototype") === -1 ? target : Doc.MakeDelegate(target); + if (altKey) { + maxLocation = this.props.Document.maximizeLocation = (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace"); + if (!maxLocation || maxLocation === "inPlace") { + let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView); + let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized, false), false); + expandedDocs.forEach(maxDoc => Doc.GetProto(maxDoc).isMinimized = false); + let hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView); + if (!hasView) { + this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(getDispDoc(maxDoc), false)); + } + expandedProtoDocs.forEach(maxDoc => maxDoc.isMinimized = wasMinimized); } } - if (!hasView && maxLocation !== "inPlace") { + if (maxLocation && maxLocation !== "inPlace") { let dataDocs = DocListCast(CollectionDockingView.Instance.props.Document.data); if (dataDocs) { - expandedDocs.forEach(maxDoc => { - if (!CollectionDockingView.Instance.CloseRightSplit(maxDoc)) { - this.props.addDocTab(Doc.MakeDelegate(maxDoc), maxLocation); - } - }); + expandedDocs.forEach(maxDoc => + (!CollectionDockingView.Instance.CloseRightSplit(Doc.GetProto(maxDoc)) && + this.props.addDocTab(getDispDoc(maxDoc), maxLocation))); } } else { - this.toggleIcon(expandedDocs); + this.toggleIcon(expandedProtoDocs); } } else if (linkedToDocs.length || linkedFromDocs.length) { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index a7aa571f8..020f764a2 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -177,6 +177,12 @@ export namespace Doc { return r || r2 || r3 || r4 ? true : false; } + // gets the document's prototype or returns the document if it is a prototype + export function GetProto(doc: Doc) { + return Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto! : doc; + } + + export function MakeAlias(doc: Doc) { const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : undefined; const alias = new Doc; -- cgit v1.2.3-70-g09d2 From 3f12e4a4b776010e09d12a1adfb1d243675bcd6e Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sun, 19 May 2019 01:15:22 -0400 Subject: Reorganized some stuff to hopefully make circular imports harder --- src/client/documents/Documents.ts | 33 ++++++++++++++++++++++ src/client/views/nodes/DocumentView.tsx | 4 +-- src/client/views/nodes/FormattedTextBox.tsx | 3 +- src/debug/Viewer.tsx | 44 ----------------------------- src/new_fields/Doc.ts | 31 -------------------- 5 files changed, 37 insertions(+), 78 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ed260d42e..0ebf6ff75 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -34,6 +34,7 @@ import { StrokeData, InkField } from "../../new_fields/InkField"; import { dropActionType } from "../util/DragManager"; import { DateField } from "../../new_fields/DateField"; import { schema } from "prosemirror-schema-basic"; +import { UndoManager } from "../util/UndoManager"; export interface DocumentOptions { x?: number; @@ -64,6 +65,38 @@ export interface DocumentOptions { } const delegateKeys = ["x", "y", "width", "height", "panX", "panY"]; +export namespace DocUtils { + export function MakeLink(source: Doc, target: Doc) { + let protoSrc = source.proto ? source.proto : source; + let protoTarg = target.proto ? target.proto : target; + UndoManager.RunInBatch(() => { + let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 }); + //let linkDoc = new Doc; + linkDoc.proto!.title = "-link name-"; + linkDoc.proto!.linkDescription = ""; + linkDoc.proto!.linkTags = "Default"; + + linkDoc.proto!.linkedTo = target; + linkDoc.proto!.linkedFrom = source; + + let linkedFrom = Cast(protoTarg.linkedFromDocs, listSpec(Doc)); + if (!linkedFrom) { + protoTarg.linkedFromDocs = linkedFrom = new List(); + } + linkedFrom.push(linkDoc); + + let linkedTo = Cast(protoSrc.linkedToDocs, listSpec(Doc)); + if (!linkedTo) { + protoSrc.linkedToDocs = linkedTo = new List(); + } + linkedTo.push(linkDoc); + return linkDoc; + }, "make link"); + } + + +} + export namespace Docs { let textProto: Doc; let histoProto: Doc; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 760e31b49..ccf09f999 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -11,7 +11,7 @@ import { BoolCast, Cast, FieldValue, StrCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { emptyFunction, Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; -import { Docs } from "../../documents/Documents"; +import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager, dropActionType } from "../../util/DragManager"; import { SearchUtil } from "../../util/SearchUtil"; @@ -264,7 +264,7 @@ export class DocumentView extends DocComponent(Docu dst.nativeHeight = src.nativeHeight; } else { - Doc.MakeLink(sourceDoc, destDoc); + DocUtils.MakeLink(sourceDoc, destDoc); de.data.droppedDocuments.push(destDoc); } e.stopPropagation(); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 98abde89e..d15813f9a 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -28,6 +28,7 @@ import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); +import { DocUtils } from '../../documents/Documents'; library.add(faEdit); library.add(faSmile); @@ -116,7 +117,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.Document; - Doc.MakeLink(sourceDoc, destDoc); + DocUtils.MakeLink(sourceDoc, destDoc); de.data.droppedDocuments.push(destDoc); e.stopPropagation(); } diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index d9b07aac6..720e1640a 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -3,56 +3,12 @@ import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { observer } from 'mobx-react'; -import { CurrentUserUtils } from '../server/authentication/models/current_user_utils'; -import { RouteStore } from '../server/RouteStore'; -import { emptyFunction } from '../Utils'; -import { Docs } from '../client/documents/Documents'; -import { SetupDrag } from '../client/util/DragManager'; -import { Transform } from '../client/util/Transform'; -import { UndoManager } from '../client/util/UndoManager'; -import { PresentationView } from '../client/views/PresentationView'; -import { CollectionDockingView } from '../client/views/collections/CollectionDockingView'; -import { ContextMenu } from '../client/views/ContextMenu'; -import { DocumentDecorations } from '../client/views/DocumentDecorations'; -import { InkingControl } from '../client/views/InkingControl'; -import { MainOverlayTextBox } from '../client/views/MainOverlayTextBox'; -import { DocumentView } from '../client/views/nodes/DocumentView'; -import { PreviewCursor } from '../client/views/PreviewCursor'; -import { SearchBox } from '../client/views/SearchBox'; -import { SelectionManager } from '../client/util/SelectionManager'; import { Doc, Field, FieldResult } from '../new_fields/Doc'; -import { Cast } from '../new_fields/Types'; import { DocServer } from '../client/DocServer'; -import { listSpec } from '../new_fields/Schema'; import { Id } from '../new_fields/RefField'; -import { HistoryUtil } from '../client/util/History'; import { List } from '../new_fields/List'; import { URLField } from '../new_fields/URLField'; -CurrentUserUtils; -RouteStore; -emptyFunction; -Docs; -SetupDrag; -Transform; -UndoManager; -PresentationView; -CollectionDockingView; -ContextMenu; -DocumentDecorations; -InkingControl; -MainOverlayTextBox; -DocumentView; -PreviewCursor; -SearchBox; -SelectionManager; -Doc; -Cast; -DocServer; -listSpec; -Id; -HistoryUtil; - configure({ enforceActions: "observed" }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 020f764a2..c6fa31a99 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -4,12 +4,9 @@ import { autoObject, SerializationHelper, Deserializable } from "../client/util/ import { DocServer } from "../client/DocServer"; import { setter, getter, getField, updateFunction, deleteProperty } from "./util"; import { Cast, ToConstructor, PromiseValue, FieldValue, NumCast } from "./Types"; -import { UndoManager, undoBatch } from "../client/util/UndoManager"; import { listSpec } from "./Schema"; -import { List } from "./List"; import { ObjectField, Parent, OnUpdate } from "./ObjectField"; import { RefField, FieldId, Id, HandleUpdate } from "./RefField"; -import { Docs } from "../client/documents/Documents"; export function IsField(field: any): field is Field { return (typeof field === "string") @@ -221,34 +218,6 @@ export namespace Doc { return copy; } - export function MakeLink(source: Doc, target: Doc) { - let protoSrc = source.proto ? source.proto : source; - let protoTarg = target.proto ? target.proto : target; - UndoManager.RunInBatch(() => { - let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 }); - //let linkDoc = new Doc; - linkDoc.proto!.title = "-link name-"; - linkDoc.proto!.linkDescription = ""; - linkDoc.proto!.linkTags = "Default"; - - linkDoc.proto!.linkedTo = target; - linkDoc.proto!.linkedFrom = source; - - let linkedFrom = Cast(protoTarg.linkedFromDocs, listSpec(Doc)); - if (!linkedFrom) { - protoTarg.linkedFromDocs = linkedFrom = new List(); - } - linkedFrom.push(linkDoc); - - let linkedTo = Cast(protoSrc.linkedToDocs, listSpec(Doc)); - if (!linkedTo) { - protoSrc.linkedToDocs = linkedTo = new List(); - } - linkedTo.push(linkDoc); - return linkDoc; - }, "make link"); - } - export function MakeDelegate(doc: Doc): Doc; export function MakeDelegate(doc: Opt): Opt; export function MakeDelegate(doc: Opt): Opt { -- cgit v1.2.3-70-g09d2 From 12796ace87581ffeac9d67fa5d7ebff8cecd1a52 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 19 May 2019 11:33:42 -0400 Subject: added opaque background for non-annotation collections. fixed marquee view when there's zoomBasis, fixed double-click opening to stopPropagation. got rid of RIGHT_BTN_DRAG stuff. --- .../views/collections/CollectionBaseView.tsx | 4 ++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 11 +++-------- .../collections/collectionFreeForm/MarqueeView.tsx | 23 ++++++++-------------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 3 ++- src/client/views/nodes/DocumentView.tsx | 5 +---- 5 files changed, 16 insertions(+), 30 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 76270f2e8..54e76fd5e 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -89,7 +89,7 @@ export class CollectionBaseView extends React.Component { } return false; } - @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } + @computed get isAnnotationOverlay() { return this.props.fieldKey === "annotations"; } @action.bound addDocument(doc: Doc, allowDuplicates: boolean = false): boolean { @@ -114,7 +114,7 @@ export class CollectionBaseView extends React.Component { } // set the ZoomBasis only if hasn't already been set -- bcz: maybe set/resetting the ZoomBasis should be a parameter to addDocument? if (!alreadyAdded && (this.collectionViewType === CollectionViewType.Freeform || this.collectionViewType === CollectionViewType.Invalid)) { - let zoom = NumCast(this.props.Document.scale, 1) / this.props.ScreenToLocalTransform().Scale;// ; + let zoom = NumCast(this.props.Document.scale, 1); Doc.SetOnPrototype(doc, "zoomBasis", zoom); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index b4b811da4..9cb8443f4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -37,7 +37,6 @@ const PanZoomDocument = makeInterface(panZoomSchema, positionSchema, pageSchema) @observer export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { - public static RIGHT_BTN_DRAG = false; private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type) private _lastX: number = 0; private _lastY: number = 0; @@ -46,8 +45,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @computed get nativeWidth() { return this.Document.nativeWidth || 0; } @computed get nativeHeight() { return this.Document.nativeHeight || 0; } + public get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; } - private get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } private panX = () => this.Document.panX || 0; private panY = () => this.Document.panY || 0; private zoomScaling = () => this.Document.scale || 1; @@ -66,7 +65,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return true; } private selectDocuments = (docs: Doc[]) => { - SelectionManager.DeselectAll; + SelectionManager.DeselectAll(); docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).filter(dv => dv).map(dv => SelectionManager.SelectDoc(dv!, true)); } @@ -112,11 +111,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerDown = (e: React.PointerEvent): void => { - if ((CollectionFreeFormView.RIGHT_BTN_DRAG && - (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) || - (e.button === 0 && e.altKey)) && this.props.active())) || - (!CollectionFreeFormView.RIGHT_BTN_DRAG && - ((e.button === 0 && !e.shiftKey && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) && this.props.active()))) { + if (e.button === 0 && !e.shiftKey && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1) && this.props.active()) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index d102c8af2..4587c2227 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -132,17 +132,18 @@ export class MarqueeView extends React.Component this._downY = this._lastY = e.pageY; this._commandExecuted = false; PreviewCursor.Visible = false; - if ((CollectionFreeFormView.RIGHT_BTN_DRAG && e.button === 0 && !e.altKey && !e.metaKey && this.props.container.props.active()) || - (!CollectionFreeFormView.RIGHT_BTN_DRAG && (e.button === 2 || (e.button === 0 && e.altKey)) && this.props.container.props.active())) { + if (e.button === 2 || (e.button === 0 && e.altKey)) { + if (!this.props.container.props.active()) this.props.selectDocuments([this.props.container.props.Document]); document.addEventListener("pointermove", this.onPointerMove, true); document.addEventListener("pointerup", this.onPointerUp, true); document.addEventListener("keydown", this.marqueeCommand, true); - // bcz: do we need this? it kills the context menu on the main collection + if (e.altKey) { + e.stopPropagation(); + e.preventDefault(); + } + // bcz: do we need this? it kills the context menu on the main collection if !altKey // e.stopPropagation(); } - if (e.altKey) { - e.preventDefault(); - } } @action @@ -248,6 +249,7 @@ export class MarqueeView extends React.Component panX: 0, panY: 0, borderRounding: e.key === "e" ? -1 : undefined, + backgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white", scale: zoomBasis, width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, @@ -275,15 +277,6 @@ export class MarqueeView extends React.Component //this.props.addDocument(newCollection, false); summary.proto!.summarizedDocs = new List(selected); summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight" - //summary.proto!.isButton = true; - //let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); - // selected.map(summarizedDoc => { - // let maxx = NumCast(summarizedDoc.x, undefined); - // let maxy = NumCast(summarizedDoc.y, undefined); - // let maxw = NumCast(summarizedDoc.width, undefined); - // let maxh = NumCast(summarizedDoc.height, undefined); - // summarizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]); - // }); this.props.addLiveTextDocument(summary); }); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 7cb4c1dfe..8851e4b93 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -180,8 +180,9 @@ export class CollectionFreeFormDocumentView extends DocComponent { document.removeEventListener("pointerup", this.onPointerUp); - if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { + if (!(e as any).propagationIsStopped && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { this.props.addDocTab(this.props.Document, "inTab"); + (e as any).propagationIsStopped = true; } e.stopPropagation(); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 760e31b49..bb5daaf4e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -187,9 +187,6 @@ export class DocumentView extends DocComponent(Docu onPointerDown = (e: React.PointerEvent): void => { this._downX = e.clientX; this._downY = e.clientY; - if (CollectionFreeFormView.RIGHT_BTN_DRAG && (e.button === 2 || (e.button === 0 && e.altKey)) && !this.isSelected()) { - return; - } this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0; if (e.shiftKey && e.buttons === 1) { CollectionDockingView.Instance.StartOtherDrag([Doc.MakeAlias(this.props.Document)], e); @@ -207,7 +204,7 @@ export class DocumentView extends DocComponent(Docu if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); - if (!e.altKey && !this.topMost && (!CollectionFreeFormView.RIGHT_BTN_DRAG && e.buttons === 1) || (CollectionFreeFormView.RIGHT_BTN_DRAG && e.buttons === 2)) { + if (!e.altKey && !this.topMost && e.buttons === 1) { this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitExpander); } } -- cgit v1.2.3-70-g09d2 From 01a223f2e6685506cc1e5db69e9062d5ff0d3246 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 19 May 2019 13:43:37 -0400 Subject: fixed dragging out tree view to drag out user document. fixed opening collections in a tab to show same layout as outside the tab. --- src/client/views/MainView.tsx | 3 ++- src/client/views/collections/CollectionDockingView.tsx | 16 ++++++++++++++-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 16 +++++++++------- 3 files changed, 25 insertions(+), 10 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index bdd3e9650..cdb105e21 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -214,7 +214,8 @@ export class MainView extends React.Component { let addTextNode = action(() => Docs.TextDocument({ borderRounding: -1, width: 200, height: 200, title: "a text note" })); let addColNode = action(() => Docs.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); let addSchemaNode = action(() => Docs.SchemaDocument(["title"], [], { width: 200, height: 200, title: "a schema collection" })); - let addTreeNode = action(() => Docs.TreeDocument([CurrentUserUtils.UserDocument], { width: 250, height: 400, title: "Library:" + CurrentUserUtils.email, dropAction: "alias" })); + let addTreeNode = action(() => CurrentUserUtils.UserDocument); + //let addTreeNode = action(() => Docs.TreeDocument([CurrentUserUtils.UserDocument], { width: 250, height: 400, title: "Library:" + CurrentUserUtils.email, dropAction: "alias" })); // let addTreeNode = action(() => Docs.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", dropAction: "copy" })); let addVideoNode = action(() => Docs.VideoDocument(videourl, { width: 200, title: "video node" })); let addPDFNode = action(() => Docs.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index eeec3eaf0..06b262d79 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -20,6 +20,7 @@ import { SubCollectionViewProps } from "./CollectionSubView"; import React = require("react"); import { ParentDocSelector } from './ParentDocumentSelector'; import { DocumentManager } from '../../util/DocumentManager'; +import { CollectionViewType } from './CollectionBaseView'; @observer export class CollectionDockingView extends React.Component { @@ -431,10 +432,21 @@ export class DockedFrameRenderer extends React.Component { if (this._mainCont.current && this._mainCont.current.children) { let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current.children[0].firstChild as HTMLElement); scale = Utils.GetScreenTransform(this._mainCont.current).scale; - return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this.contentScaling()); + return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / scale); } return Transform.Identity(); } + get scaleToFitMultiplier() { + let docWidth = NumCast(this._document!.width); + let docHeight = NumCast(this._document!.height); + if (NumCast(this._document!.nativeWidth) || !docWidth || !this._panelWidth || !this._panelHeight) return 1; + if (StrCast(this._document!.layout).indexOf("Collection") === -1 || + NumCast(this._document!.viewType) !== CollectionViewType.Freeform) return 1; + let scaling = Math.max(1, this._panelWidth / docWidth * docHeight > this._panelHeight ? + this._panelHeight / docHeight : this._panelWidth / docWidth); + console.log("Scaling = " + scaling); + return scaling; + } get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } addDocTab = (doc: Doc, location: string) => { @@ -450,7 +462,7 @@ export class DockedFrameRenderer extends React.Component { } return (
+ style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px) scale(${this.scaleToFitMultiplier}, ${this.scaleToFitMultiplier})` }}> (); private _downX: number = 0; private _downY: number = 0; + private _doubleTap = false; + private _lastTap: number = 0; _bringToFrontDisposer?: IReactionDisposer; @computed get transform() { @@ -159,18 +161,16 @@ export class CollectionFreeFormDocumentView extends DocComponent { this._downX = e.clientX; this._downY = e.clientY; + this._doubleTap = false; if (e.button === 0 && e.altKey) { e.stopPropagation(); // prevents panning from happening on collection if shift is pressed after a document drag has started } // allow pointer down to go through otherwise so that marquees can be drawn starting over a document if (Date.now() - this._lastTap < 300) { if (e.buttons === 1) { - this._downX = e.clientX; - this._downY = e.clientY; document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); } @@ -180,14 +180,16 @@ export class CollectionFreeFormDocumentView extends DocComponent { document.removeEventListener("pointerup", this.onPointerUp); - if (!(e as any).propagationIsStopped && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { - this.props.addDocTab(this.props.Document, "inTab"); - (e as any).propagationIsStopped = true; + if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { + this._doubleTap = true; } - e.stopPropagation(); } onClick = async (e: React.MouseEvent) => { e.stopPropagation(); + if (this._doubleTap) { + this.props.addDocTab(this.props.Document, "inTab"); + SelectionManager.DeselectAll(); + } let altKey = e.altKey; if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { -- cgit v1.2.3-70-g09d2 From f53ba030a86bf3fc384ff3c00efcf3c1f0497b9b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 19 May 2019 18:10:53 -0400 Subject: cleaned up context menu icons. --- src/client/views/ContextMenu.scss | 3 ++- src/client/views/ContextMenu.tsx | 1 - src/client/views/ContextMenuItem.tsx | 3 +-- .../views/collections/CollectionDockingView.tsx | 1 - src/client/views/collections/CollectionView.tsx | 8 ++++--- src/client/views/nodes/DocumentView.tsx | 28 +++++++++++++--------- 6 files changed, 25 insertions(+), 19 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 0a14c8ce7..b12ee3faa 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -48,7 +48,7 @@ border-style: none; border-color: $intermediate-color; // rgb(187, 186, 186); border-bottom-style: solid; - padding: 10px; + padding: 10px 0px 10px 0px; white-space: nowrap; font-size: 1vw; } @@ -67,4 +67,5 @@ .icon-background { background-color: #DDDDDD; + margin-right: 2px; } \ No newline at end of file diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 9143c012e..84c17a642 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -90,7 +90,6 @@ export class ContextMenu extends React.Component {
- diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index ed583942a..b9239dac9 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -37,8 +37,7 @@ export class ContextMenuItem extends React.Component { return (
- - {this.props.icon ? : null} + {this.props.icon ? : }
{this.props.description}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 06b262d79..483209f86 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -444,7 +444,6 @@ export class DockedFrameRenderer extends React.Component { NumCast(this._document!.viewType) !== CollectionViewType.Freeform) return 1; let scaling = Math.max(1, this._panelWidth / docWidth * docHeight > this._panelHeight ? this._panelHeight / docHeight : this._panelWidth / docWidth); - console.log("Scaling = " + scaling); return scaling; } get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index b9ffc11a2..59c763be8 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faProjectDiagram, faSquare, faTh, faTree } from '@fortawesome/free-solid-svg-icons'; +import { faProjectDiagram, faSquare, faTh, faTree, faSignature, faThList } from '@fortawesome/free-solid-svg-icons'; import { observer } from "mobx-react"; import * as React from 'react'; import { Id } from '../../../new_fields/RefField'; @@ -18,6 +18,8 @@ library.add(faTh); library.add(faTree); library.add(faSquare); library.add(faProjectDiagram); +library.add(faSignature); +library.add(faThList); @observer export class CollectionView extends React.Component { @@ -40,11 +42,11 @@ export class CollectionView extends React.Component { onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Freeform), icon: "project-diagram" }); + ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Freeform), icon: "signature" }); if (CollectionBaseView.InSafeMode()) { ContextMenu.Instance.addItem({ description: "Test Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Invalid), icon: "project-diagram" }); } - ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "project-diagram" }); + ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "th-list" }); ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree), icon: "tree" }); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 38f3db19f..9e86b411e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faAlignCenter, faCaretSquareRight, faCompressArrowsAlt, faExpandArrowsAlt, faLayerGroup, faSquare, faTrash } from '@fortawesome/free-solid-svg-icons'; +import { faAlignCenter, faCaretSquareRight, faCompressArrowsAlt, faExpandArrowsAlt, faLayerGroup, faSquare, faTrash, faConciergeBell, faFolder, faMapPin, faLink, faFingerprint, faCrosshairs, faDesktop } from '@fortawesome/free-solid-svg-icons'; import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; @@ -19,7 +19,6 @@ import { SelectionManager } from "../../util/SelectionManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; @@ -39,6 +38,13 @@ library.add(faLayerGroup); library.add(faAlignCenter); library.add(faCaretSquareRight); library.add(faSquare); +library.add(faConciergeBell); +library.add(faFolder); +library.add(faMapPin); +library.add(faLink); +library.add(faFingerprint); +library.add(faCrosshairs); +library.add(faDesktop); const linkSchema = createSchema({ title: "string", @@ -308,21 +314,21 @@ export class DocumentView extends DocComponent(Docu e.preventDefault(); const cm = ContextMenu.Instance; - cm.addItem({ description: "Full Screen", event: this.fullScreenClicked, icon: "expand-arrows-alt" }); - cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeButton, icon: "expand-arrows-alt" }); - cm.addItem({ description: "Fields", event: this.fieldsClicked, icon: "layer-group" }); - cm.addItem({ description: "Center", event: () => this.props.focus(this.props.Document), icon: "align-center" }); - cm.addItem({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "inTab"), icon: "expand-arrows-alt" }); + cm.addItem({ description: "Full Screen", event: this.fullScreenClicked, icon: "desktop" }); + cm.addItem({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "inTab"), icon: "folder" }); cm.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document), icon: "caret-square-right" }); + cm.addItem({ description: "Fields", event: this.fieldsClicked, icon: "layer-group" }); + cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); + cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeButton, icon: "concierge-bell" }); cm.addItem({ description: "Find aliases", event: async () => { const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); CollectionDockingView.Instance.AddRightSplit(Docs.SchemaDocument(["title"], aliases, {})); - }, icon: "expand-arrows-alt" + }, icon: "search" }); - cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])), icon: "expand-arrows-alt" }); - cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "expand-arrows-alt" }); - cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "expand-arrows-alt" }); + cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document), icon: "crosshairs" }); + cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); + cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" }); if (!this.topMost) { // DocumentViews should stop propagation of this event -- cgit v1.2.3-70-g09d2 From c103acbe8f8df919e87f9a18872a94eb8bc1a001 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 19 May 2019 19:55:26 -0400 Subject: fixed some small things with presentation and icon --- src/client/views/DocumentDecorations.tsx | 6 +++--- src/client/views/MainView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 3 ++- src/client/views/nodes/IconBox.tsx | 1 - 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 5ec090f05..319e91337 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -276,16 +276,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let doc = selected[0].props.Document; let iconDoc = Docs.IconDocument(layoutString); iconDoc.isButton = true; - iconDoc.proto!.title = selected.length > 1 ? "ICONset" : "ICON" + StrCast(doc.title); + iconDoc.proto!.title = selected.length > 1 ? "-multiple-.icon" : StrCast(doc.title) + ".icon"; iconDoc.labelField = selected.length > 1 ? undefined : this._fieldKey; - iconDoc.proto![this._fieldKey] = selected.length > 1 ? "collection" : undefined; + //iconDoc.proto![this._fieldKey] = selected.length > 1 ? "collection" : undefined; iconDoc.proto!.isMinimized = false; iconDoc.width = Number(MINIMIZED_ICON_SIZE); iconDoc.height = Number(MINIMIZED_ICON_SIZE); iconDoc.x = NumCast(doc.x); iconDoc.y = NumCast(doc.y) - 24; iconDoc.maximizedDocs = new List(selected.map(s => s.props.Document.proto!)); - doc.minimizedDoc = iconDoc; + selected.length === 1 && (doc.minimizedDoc = iconDoc); selected[0].props.addDocument && selected[0].props.addDocument(iconDoc, false); return iconDoc; } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index cdb105e21..400562f12 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -47,7 +47,7 @@ export class MainView extends React.Component { private set mainContainer(doc: Opt) { if (doc) { if (!("presentationView" in doc)) { - doc.presentationView = new Doc(); + doc.presentationView = Docs.TreeDocument([], { title: "Presentation" }); } CurrentUserUtils.UserDocument.activeWorkspace = doc; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9e86b411e..5f218fd1f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -128,7 +128,8 @@ export class DocumentView extends DocComponent(Docu }); } // bcz: kind of ugly .. setup a reaction to update the title of a summary document's target (maximizedDocs) whenver the summary doc's title changes - this._reactionDisposer = reaction(() => [this.props.Document.maximizedDocs, this.props.Document.summaryDoc, this.props.Document.summaryDoc instanceof Doc ? this.props.Document.summaryDoc.title : ""], + this._reactionDisposer = reaction(() => [DocListCast(this.props.Document.maximizedDocs).map(md => md.title), + this.props.Document.summaryDoc, this.props.Document.summaryDoc instanceof Doc ? this.props.Document.summaryDoc.title : ""], () => { let maxDoc = DocListCast(this.props.Document.maximizedDocs); if (maxDoc.length === 1 && StrCast(this.props.Document.title).startsWith("-") && StrCast(this.props.Document.layout).indexOf("IconBox") !== -1) { diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index b42eb44a5..00021bc78 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -12,7 +12,6 @@ import { IconField } from "../../../new_fields/IconField"; import { ContextMenu } from "../ContextMenu"; import Measure from "react-measure"; import { MINIMIZED_ICON_SIZE } from "../../views/globalCssVariables.scss"; -import { listSpec } from "../../../new_fields/Schema"; library.add(faCaretUp); -- cgit v1.2.3-70-g09d2 From b789ac4cc3fe013139825f811d7574e1d305c2cc Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sun, 19 May 2019 20:30:50 -0400 Subject: Added link follow behavior --- src/client/util/DocumentManager.ts | 7 ++++--- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index d06af6dd5..be448098a 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -115,7 +115,7 @@ export class DocumentManager { } @undoBatch - public jumpToDocument = async (docDelegate: Doc, makeCopy: boolean = true): Promise => { + public jumpToDocument = async (docDelegate: Doc, makeCopy: boolean = true, dockFunc?: (doc: Doc) => void): Promise => { let doc = docDelegate.proto ? docDelegate.proto : docDelegate; const page = NumCast(doc.page, undefined); const contextDoc = await Cast(doc.annotationOn, Doc); @@ -128,14 +128,15 @@ export class DocumentManager { docView.props.focus(docView.props.Document); } else { if (!contextDoc) { - CollectionDockingView.Instance.AddRightSplit(docDelegate ? (makeCopy ? Doc.MakeCopy(docDelegate) : docDelegate) : Doc.MakeDelegate(doc)); + const actualDoc = docDelegate ? (makeCopy ? Doc.MakeCopy(docDelegate) : docDelegate) : Doc.MakeDelegate(doc); + (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); } else { let contextView = DocumentManager.Instance.getDocumentView(contextDoc); if (contextView) { contextDoc.panTransformType = "Ease"; contextView.props.focus(contextDoc); } else { - CollectionDockingView.Instance.AddRightSplit(contextDoc); + (dockFunc || CollectionDockingView.Instance.AddRightSplit)(contextDoc); } } } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index fa44ec9f3..5bff08280 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -239,7 +239,8 @@ export class CollectionFreeFormDocumentView extends DocComponent this.props.addDocTab(document, maxLocation)); } } } -- cgit v1.2.3-70-g09d2 From af2346983eae1145167b70faf96a9aec0ca82427 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 20 May 2019 00:09:47 -0400 Subject: Fixed a bunch of demo bugs Moved Field Symbols to separate file Editing is mostly working in debug viewer --- deploy/debug/viewer.html | 1 + src/client/DocServer.ts | 3 +- src/client/northstar/dash-fields/HistogramField.ts | 7 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- src/client/util/DocumentManager.ts | 2 +- src/client/util/SearchUtil.ts | 2 +- src/client/util/TooltipTextMenu.tsx | 2 +- src/client/util/type_decls.d | 128 +++++++-------------- src/client/views/EditableView.tsx | 10 +- src/client/views/MainView.tsx | 2 +- src/client/views/PresentationView.tsx | 2 +- src/client/views/SearchBox.tsx | 2 +- .../views/collections/CollectionBaseView.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 14 ++- src/client/views/collections/CollectionPDFView.tsx | 2 +- .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 2 +- .../views/collections/CollectionVideoView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../views/collections/ParentDocumentSelector.tsx | 2 +- .../CollectionFreeFormLinksView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 3 - src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/KeyValueBox.tsx | 4 +- src/client/views/nodes/KeyValuePair.tsx | 4 +- src/client/views/nodes/LinkMenu.tsx | 2 +- src/debug/Viewer.tsx | 53 +++++++-- src/new_fields/CursorField.ts | 7 +- src/new_fields/DateField.ts | 7 +- src/new_fields/Doc.ts | 43 ++++--- src/new_fields/FieldSymbols.ts | 10 ++ src/new_fields/HtmlField.ts | 7 +- src/new_fields/IconField.ts | 7 +- src/new_fields/InkField.ts | 7 +- src/new_fields/List.ts | 16 ++- src/new_fields/ObjectField.ts | 7 +- src/new_fields/Proxy.ts | 9 +- src/new_fields/RefField.ts | 5 +- src/new_fields/RichTextField.ts | 7 +- src/new_fields/URLField.ts | 9 +- src/new_fields/util.ts | 7 +- 42 files changed, 240 insertions(+), 173 deletions(-) create mode 100644 src/new_fields/FieldSymbols.ts (limited to 'src/client/views/nodes') diff --git a/deploy/debug/viewer.html b/deploy/debug/viewer.html index 3785a6602..8c265ccb8 100644 --- a/deploy/debug/viewer.html +++ b/deploy/debug/viewer.html @@ -3,6 +3,7 @@ Document Debugger + diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index f1b50d5a0..cbcf751ee 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -3,7 +3,8 @@ import { MessageStore } from "./../server/Message"; import { Opt } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; -import { RefField, HandleUpdate, Id } from '../new_fields/RefField'; +import { RefField } from '../new_fields/RefField'; +import { Id, HandleUpdate } from '../new_fields/FieldSymbols'; export namespace DocServer { const _cache: { [id: string]: RefField | Promise> } = {}; diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 1ee2189b9..31040a474 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -3,10 +3,11 @@ import { custom, serializable } from "serializr"; import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel"; import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation"; -import { ObjectField, Copy } from "../../../new_fields/ObjectField"; +import { ObjectField } from "../../../new_fields/ObjectField"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { OmitKeys } from "../../../Utils"; import { Deserializable } from "../../util/SerializationHelper"; +import { Copy, ToScriptString } from "../../../new_fields/FieldSymbols"; function serialize(field: HistogramField) { let obj = OmitKeys(field, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit; @@ -55,4 +56,8 @@ export class HistogramField extends ObjectField { let z = this.HistoOp.Copy; return new HistogramField(HistogramOperation.Duplicate(this.HistoOp)); } + + [ToScriptString]() { + return "invalid"; + } } \ No newline at end of file diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index eb1ad69b7..a9646ed31 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -19,7 +19,7 @@ import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives"; import { StyleConstants } from "../utils/StyleContants"; import { Cast } from "../../../new_fields/Types"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; @observer diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index be448098a..a5e768dcf 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -5,10 +5,10 @@ import { FieldValue, Cast, NumCast, BoolCast } from '../../new_fields/Types'; import { listSpec } from '../../new_fields/Schema'; import { undoBatch } from './UndoManager'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; -import { Id } from '../../new_fields/RefField'; import { CollectionView } from '../views/collections/CollectionView'; import { CollectionPDFView } from '../views/collections/CollectionPDFView'; import { CollectionVideoView } from '../views/collections/CollectionVideoView'; +import { Id } from '../../new_fields/FieldSymbols'; export class DocumentManager { diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 4ccff0d1b..e8eb70837 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -1,7 +1,7 @@ import * as rp from 'request-promise'; import { DocServer } from '../DocServer'; import { Doc } from '../../new_fields/Doc'; -import { Id } from '../../new_fields/RefField'; +import { Id } from '../../new_fields/FieldSymbols'; export namespace SearchUtil { export function Search(query: string, returnDocs: true): Promise; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 4d40d09b2..a1f80120f 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -22,12 +22,12 @@ import { throwStatement } from "babel-types"; import { View } from "@react-pdf/renderer"; import { DragManager } from "./DragManager"; import { Doc, Opt, Field } from "../../new_fields/Doc"; -import { Id } from "../../new_fields/RefField"; import { Utils } from "../northstar/utils/Utils"; import { DocServer } from "../DocServer"; import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { DocumentManager } from "./DocumentManager"; +import { Id } from "../../new_fields/FieldSymbols"; const SVG = "http://www.w3.org/2000/svg"; diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d index 47c3481b2..51114d0e2 100644 --- a/src/client/util/type_decls.d +++ b/src/client/util/type_decls.d @@ -119,104 +119,54 @@ interface URL { username: string; toJSON(): string; } +interface PromiseLike { + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): PromiseLike; +} +interface Promise { + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; +} -declare type FieldId = string; +declare const Update: unique symbol; +declare const Self: unique symbol; +declare const SelfProxy: unique symbol; +declare const HandleUpdate: unique symbol; +declare const Id: unique symbol; +declare const OnUpdate: unique symbol; +declare const Parent: unique symbol; +declare const Copy: unique symbol; +declare const ToScriptString: unique symbol; -declare abstract class Field { - Id: FieldId; - abstract ToScriptString(): string; - abstract TrySetValue(value: any): boolean; - abstract GetValue(): any; - abstract Copy(): Field; -} +declare abstract class RefField { + readonly [Id]: FieldId; + + constructor(id?: FieldId); + protected [HandleUpdate]?(diff: any): void; -declare abstract class BasicField extends Field { - constructor(data: T); - Data: T; - TrySetValue(value: any): boolean; - GetValue(): any; + abstract [ToScriptString](): string; } -declare class TextField extends BasicField{ - constructor(); - constructor(data: string); - ToScriptString(): string; - Copy(): Field; -} -declare class ImageField extends BasicField{ - constructor(); - constructor(data: URL); - ToScriptString(): string; - Copy(): Field; -} -declare class HtmlField extends BasicField{ - constructor(); - constructor(data: string); - ToScriptString(): string; - Copy(): Field; -} -declare class NumberField extends BasicField{ - constructor(); - constructor(data: number); - ToScriptString(): string; - Copy(): Field; -} -declare class WebField extends BasicField{ - constructor(); - constructor(data: URL); - ToScriptString(): string; - Copy(): Field; -} -declare class ListField extends BasicField{ - constructor(); - constructor(data: T[]); - ToScriptString(): string; - Copy(): Field; -} -declare class Key extends Field { - constructor(name:string); - Name: string; - TrySetValue(value: any): boolean; - GetValue(): any; - Copy(): Field; - ToScriptString(): string; -} -declare type FIELD_WAITING = null; -declare type Opt = T | undefined; -declare type FieldValue = Opt | FIELD_WAITING; -// @ts-ignore -declare class Document extends Field { - TrySetValue(value: any): boolean; - GetValue(): any; - Copy(): Field; - ToScriptString(): string; +declare abstract class ObjectField { + protected [OnUpdate](diff?: any): void; + private [Parent]?: RefField | ObjectField; + abstract [Copy](): ObjectField; - Width(): number; - Height(): number; - Scale(): number; - Title: string; + abstract [ToScriptString](): string; +} +declare type FieldId = string; - Get(key: Key): FieldValue; - GetAsync(key: Key, callback: (field: Field) => void): boolean; - GetOrCreateAsync(key: Key, ctor: { new(): T }, callback: (field: T) => void): void; - GetT(key: Key, ctor: { new(): T }): FieldValue; - GetOrCreate(key: Key, ctor: { new(): T }): T; - GetData(key: Key, ctor: { new(): U }, defaultVal: T): T; - GetHtml(key: Key, defaultVal: string): string; - GetNumber(key: Key, defaultVal: number): number; - GetText(key: Key, defaultVal: string): string; - GetList(key: Key, defaultVal: T[]): T[]; - Set(key: Key, field: Field | undefined): void; - SetData(key: Key, value: T, ctor: { new(): U }): void; - SetText(key: Key, value: string): void; - SetNumber(key: Key, value: number): void; - GetPrototype(): FieldValue; - GetAllPrototypes(): Document[]; - MakeDelegate(): Document; +declare type Field = number | string | boolean | ObjectField | RefField; + +declare type Opt = T | undefined; +declare class Doc extends RefField { + [key: string]: Field | undefined; + [ToScriptString](): string; } -declare const KeyStore: { - [name: string]: Key; +declare class ListImpl extends ObjectField { + [index: number]: T | (T extends RefField ? Promise : never); + [ToScriptString](): string; + [Copy](): ObjectField; } // @ts-ignore diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 78143ccda..c946d68e1 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -22,7 +22,7 @@ export interface EditableProps { * The contents to render when not editing */ contents: any; - height: number; + height?: number; display?: string; oneLine?: boolean; } @@ -53,6 +53,12 @@ export class EditableView extends React.Component { } } + @action + onClick = (e: React.MouseEvent) => { + this.editing = true; + e.stopPropagation(); + } + render() { if (this.editing) { return this.editing = false)} @@ -60,7 +66,7 @@ export class EditableView extends React.Component { } else { return (
this.editing = true)} > + onClick={this.onClick} > {this.props.contents}
); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 400562f12..9edbba997 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -29,7 +29,7 @@ import { FieldResult, Field, Doc, Opt } from '../../new_fields/Doc'; import { Cast, FieldValue, StrCast } from '../../new_fields/Types'; import { DocServer } from '../DocServer'; import { listSpec } from '../../new_fields/Schema'; -import { Id } from '../../new_fields/RefField'; +import { Id } from '../../new_fields/FieldSymbols'; import { HistoryUtil } from '../util/History'; import { CollectionBaseView } from './collections/CollectionBaseView'; diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index 9c37e9000..ce679aa0a 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -7,7 +7,7 @@ import { Utils } from "../../Utils"; import { Doc, DocListCast, DocListCastAsync } from "../../new_fields/Doc"; import { listSpec } from "../../new_fields/Schema"; import { Cast, NumCast, FieldValue, PromiseValue, StrCast } from "../../new_fields/Types"; -import { Id } from "../../new_fields/RefField"; +import { Id } from "../../new_fields/FieldSymbols"; import { List } from "../../new_fields/List"; import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 6e64e1af1..8efd8d266 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -16,7 +16,7 @@ import { isString } from 'util'; import { constant } from 'async'; import { DocServer } from '../DocServer'; import { Doc } from '../../new_fields/Doc'; -import { Id } from '../../new_fields/RefField'; +import { Id } from '../../new_fields/FieldSymbols'; import { DocumentManager } from '../util/DocumentManager'; import { SetupDrag } from '../util/DragManager'; import { Docs } from '../documents/Documents'; diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 84ffbac36..5686ccfef 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -7,8 +7,8 @@ import { Cast, FieldValue, PromiseValue, NumCast } from '../../../new_fields/Typ import { Doc, FieldResult, Opt, DocListCast } from '../../../new_fields/Doc'; import { listSpec } from '../../../new_fields/Schema'; import { List } from '../../../new_fields/List'; -import { Id } from '../../../new_fields/RefField'; import { SelectionManager } from '../../util/SelectionManager'; +import { Id } from '../../../new_fields/FieldSymbols'; export enum CollectionViewType { Invalid, diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 483209f86..e904358a9 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -6,7 +6,7 @@ import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; import * as GoldenLayout from "../../../client/goldenLayout"; import { Doc, Field, Opt, DocListCast } from "../../../new_fields/Doc"; -import { FieldId, Id } from "../../../new_fields/RefField"; +import { FieldId } from "../../../new_fields/RefField"; import { listSpec } from "../../../new_fields/Schema"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { emptyFunction, returnTrue, Utils } from "../../../Utils"; @@ -21,6 +21,7 @@ import React = require("react"); import { ParentDocSelector } from './ParentDocumentSelector'; import { DocumentManager } from '../../util/DocumentManager'; import { CollectionViewType } from './CollectionBaseView'; +import { Id } from '../../../new_fields/FieldSymbols'; @observer export class CollectionDockingView extends React.Component { @@ -75,7 +76,7 @@ export class CollectionDockingView extends React.Component { let retVal = false; if (this._goldenLayout.root.contentItems[0].isRow) { retVal = Array.from(this._goldenLayout.root.contentItems[0].contentItems).some((child: any) => { @@ -118,7 +119,7 @@ export class CollectionDockingView extends React.Component { let docs = Cast(this.props.Document.data, listSpec(Doc)); if (docs) { docs.push(document); @@ -155,7 +156,7 @@ export class CollectionDockingView extends React.Component { let docs = Cast(this.props.Document.data, listSpec(Doc)); if (docs) { docs.push(document); @@ -412,10 +413,11 @@ export class DockedFrameRenderer extends React.Component { @observable private _panelWidth = 0; @observable private _panelHeight = 0; @observable private _document: Opt; - _stack: any; + get _stack(): any { + return (this.props as any).glContainer.parent.parent; + } constructor(props: any) { super(props); - this._stack = (this.props as any).glContainer.parent.parent; DocServer.GetRefField(this.props.documentId).then(action((f: Opt) => this._document = f as Doc)); } diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index a6614da21..5e51437a4 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -8,7 +8,7 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from "./CollectionBaseView"; import { emptyFunction } from "../../../Utils"; import { NumCast } from "../../../new_fields/Types"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; @observer diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index f15da41ff..b25b48339 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -23,7 +23,7 @@ import { Opt, Field, Doc, DocListCastAsync, DocListCast } from "../../../new_fie import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; import { Gateway } from "../../northstar/manager/Gateway"; import { Docs } from "../../documents/Documents"; import { ContextMenu } from "../ContextMenu"; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 72fa69cb1..8ad495762 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -11,7 +11,7 @@ import React = require("react"); import { Document, listSpec } from '../../../new_fields/Schema'; import { Cast, StrCast, BoolCast, FieldValue } from '../../../new_fields/Types'; import { Doc, DocListCast } from '../../../new_fields/Doc'; -import { Id } from '../../../new_fields/RefField'; +import { Id } from '../../../new_fields/FieldSymbols'; import { ContextMenu } from '../ContextMenu'; import { undoBatch } from '../../util/UndoManager'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 9ab959f3c..27f23a1a8 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -7,7 +7,7 @@ import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { emptyFunction } from "../../../Utils"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; import { VideoBox } from "../nodes/VideoBox"; import { NumCast } from "../../../new_fields/Types"; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 59c763be8..bfdef8e8c 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -2,7 +2,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faProjectDiagram, faSquare, faTh, faTree, faSignature, faThList } from '@fortawesome/free-solid-svg-icons'; import { observer } from "mobx-react"; import * as React from 'react'; -import { Id } from '../../../new_fields/RefField'; +import { Id } from '../../../new_fields/FieldSymbols'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../ContextMenu"; diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 52f7914f3..4d07c31a7 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -3,7 +3,7 @@ import './ParentDocumentSelector.scss'; import { Doc } from "../../../new_fields/Doc"; import { observer } from "mobx-react"; import { observable, action, runInAction } from "mobx"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; import { SearchUtil } from "../../util/SearchUtil"; import { CollectionDockingView } from "./CollectionDockingView"; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index d5ce4e1e7..e1ff715d1 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -11,7 +11,7 @@ import { Doc, DocListCastAsync, DocListCast } from "../../../../new_fields/Doc"; import { Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types"; import { listSpec } from "../../../../new_fields/Schema"; import { List } from "../../../../new_fields/List"; -import { Id } from "../../../../new_fields/RefField"; +import { Id } from "../../../../new_fields/FieldSymbols"; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9cb8443f4..ee6f4821f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -22,9 +22,9 @@ import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Sc import { Doc, WidthSym, HeightSym } from "../../../../new_fields/Doc"; import { FieldValue, Cast, NumCast, BoolCast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; -import { Id } from "../../../../new_fields/RefField"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { HistoryUtil } from "../../../util/History"; +import { Id } from "../../../../new_fields/FieldSymbols"; export const panZoomSchema = createSchema({ panX: "number", diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 4587c2227..2029b91e5 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -17,9 +17,6 @@ import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; import { ImageField } from "../../../../new_fields/URLField"; import { Template, Templates } from "../../Templates"; -import { Gateway } from "../../../northstar/manager/Gateway"; -import { DocServer } from "../../../DocServer"; -import { Id } from "../../../../new_fields/RefField"; interface MarqueeViewProps { getContainerTransform: () => Transform; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5f218fd1f..87c88f57c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -4,8 +4,7 @@ import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; -import { Copy, ObjectField } from "../../../new_fields/ObjectField"; -import { Id } from "../../../new_fields/RefField"; +import { ObjectField } from "../../../new_fields/ObjectField"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; import { BoolCast, Cast, FieldValue, StrCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; @@ -29,6 +28,7 @@ import { Template } from "./../Templates"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); +import { Id, Copy } from '../../../new_fields/FieldSymbols'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(faTrash); diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 86437a6c1..8cb576786 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -8,7 +8,7 @@ import "./KeyValueBox.scss"; import { KeyValuePair } from "./KeyValuePair"; import React = require("react"); import { NumCast, Cast, FieldValue } from "../../../new_fields/Types"; -import { Doc, IsField } from "../../../new_fields/Doc"; +import { Doc, Field } from "../../../new_fields/Doc"; @observer export class KeyValueBox extends React.Component { @@ -41,7 +41,7 @@ export class KeyValueBox extends React.Component { let res = script.run(); if (!res.success) return; const field = res.result; - if (IsField(field)) { + if (Field.IsField(field)) { realDoc[this._keyInput] = field; } this._keyInput = ""; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 4f7919f50..7a88985c0 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -9,7 +9,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import "./KeyValueBox.scss"; import "./KeyValuePair.scss"; import React = require("react"); -import { Doc, Opt, IsField } from '../../../new_fields/Doc'; +import { Doc, Opt, Field } from '../../../new_fields/Doc'; import { FieldValue } from '../../../new_fields/Types'; // Represents one row in a key value plane @@ -75,7 +75,7 @@ export class KeyValuePair extends React.Component { let res = script.run(); if (!res.success) return false; const field = res.result; - if (IsField(field)) { + if (Field.IsField(field)) { props.Document[props.fieldKey] = field; return true; } diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 4cf798249..3f09d6214 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -7,7 +7,7 @@ import './LinkMenu.scss'; import React = require("react"); import { Doc, DocListCast } from "../../../new_fields/Doc"; import { Cast, FieldValue, StrCast } from "../../../new_fields/Types"; -import { Id } from "../../../new_fields/RefField"; +import { Id } from "../../../new_fields/FieldSymbols"; interface Props { docView: DocumentView; diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index 720e1640a..4314e2132 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -3,11 +3,27 @@ import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { observer } from 'mobx-react'; -import { Doc, Field, FieldResult } from '../new_fields/Doc'; +import { Doc, Field, FieldResult, Opt } from '../new_fields/Doc'; import { DocServer } from '../client/DocServer'; -import { Id } from '../new_fields/RefField'; +import { Id } from '../new_fields/FieldSymbols'; import { List } from '../new_fields/List'; import { URLField } from '../new_fields/URLField'; +import { EditableView } from '../client/views/EditableView'; +import { CompileScript } from '../client/util/Scripting'; + +function applyToDoc(doc: { [index: string]: FieldResult }, key: string, scriptString: string): boolean; +function applyToDoc(doc: { [index: number]: FieldResult }, key: number, scriptString: string): boolean; +function applyToDoc(doc: any, key: string | number, scriptString: string): boolean { + let script = CompileScript(scriptString, { addReturn: true, params: { this: doc instanceof Doc ? Doc.name : List.name } }); + if (!script.compiled) { + return false; + } + const res = script.run({ this: doc }); + if (!res.success) return false; + if (!Field.IsField(res.result)) return false; + doc[key] = res.result; + return true; +} configure({ enforceActions: "observed" @@ -18,12 +34,18 @@ class ListViewer extends React.Component<{ field: List }>{ @observable expanded = false; + @action + onClick = (e: React.MouseEvent) => { + this.expanded = !this.expanded; + e.stopPropagation(); + } + render() { let content; if (this.expanded) { content = (
- {this.props.field.map((field, index) => )} + {this.props.field.map((field, index) => applyToDoc(this.props.field, index, value)} />)}
); } else { @@ -31,7 +53,7 @@ class ListViewer extends React.Component<{ field: List }>{ } return (
- + {content}
); @@ -42,6 +64,13 @@ class ListViewer extends React.Component<{ field: List }>{ class DocumentViewer extends React.Component<{ field: Doc }> { @observable expanded = false; + + @action + onClick = (e: React.MouseEvent) => { + this.expanded = !this.expanded; + e.stopPropagation(); + } + render() { let content; if (this.expanded) { @@ -50,7 +79,7 @@ class DocumentViewer extends React.Component<{ field: Doc }> { return (
({key}): - + applyToDoc(this.props.field, key, value)}>
); }); @@ -67,7 +96,7 @@ class DocumentViewer extends React.Component<{ field: Doc }> { } return (
- + {content}
); @@ -75,7 +104,7 @@ class DocumentViewer extends React.Component<{ field: Doc }> { } @observer -class DebugViewer extends React.Component<{ field: FieldResult }> { +class DebugViewer extends React.Component<{ field: FieldResult, setValue(value: string): boolean }> { render() { let content; @@ -90,10 +119,14 @@ class DebugViewer extends React.Component<{ field: FieldResult }> { content =

{field}

; } else if (field instanceof URLField) { content =

{field.url.href}

; + } else if (field instanceof Promise) { + return

Field loading

; } else { - content =

Unrecognized field type

; + return

Unrecognized field type

; } - return content; + + return Field.toScriptString(field)} SetValue={this.props.setValue} + contents={content}>; } } @@ -129,7 +162,7 @@ class Viewer extends React.Component { onChange={this.inputOnChange} onKeyDown={this.onKeyPress} />
- {this.fields.map((field, index) => )} + {this.fields.map((field, index) => false}>)}
); diff --git a/src/new_fields/CursorField.ts b/src/new_fields/CursorField.ts index fc144222c..1be1ec3e0 100644 --- a/src/new_fields/CursorField.ts +++ b/src/new_fields/CursorField.ts @@ -1,7 +1,8 @@ -import { ObjectField, Copy, OnUpdate } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; import { observable } from "mobx"; import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, createSimpleSchema, object } from "serializr"; +import { OnUpdate, ToScriptString, Copy } from "./FieldSymbols"; export type CursorPosition = { x: number, @@ -52,4 +53,8 @@ export default class CursorField extends ObjectField { [Copy]() { return new CursorField(this.data); } + + [ToScriptString]() { + return "invalid"; + } } \ No newline at end of file diff --git a/src/new_fields/DateField.ts b/src/new_fields/DateField.ts index c0a79f267..fc8abb9d9 100644 --- a/src/new_fields/DateField.ts +++ b/src/new_fields/DateField.ts @@ -1,6 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, date } from "serializr"; -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString } from "./FieldSymbols"; @Deserializable("date") export class DateField extends ObjectField { @@ -15,4 +16,8 @@ export class DateField extends ObjectField { [Copy]() { return new DateField(this.date); } + + [ToScriptString]() { + return `new DateField(new Date(${this.date.toISOString()}))`; + } } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 02dd34cb4..f4514c33e 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -5,27 +5,33 @@ import { DocServer } from "../client/DocServer"; import { setter, getter, getField, updateFunction, deleteProperty } from "./util"; import { Cast, ToConstructor, PromiseValue, FieldValue, NumCast } from "./Types"; import { listSpec } from "./Schema"; -import { ObjectField, Parent, OnUpdate } from "./ObjectField"; -import { RefField, FieldId, Id, HandleUpdate } from "./RefField"; - -export function IsField(field: any): field is Field { - return (typeof field === "string") - || (typeof field === "number") - || (typeof field === "boolean") - || (field instanceof ObjectField) - || (field instanceof RefField); +import { ObjectField } from "./ObjectField"; +import { RefField, FieldId } from "./RefField"; +import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id } from "./FieldSymbols"; + +export namespace Field { + export function toScriptString(field: Field): string { + if (typeof field === "string") { + return `"${field}"`; + } else if (typeof field === "number" || typeof field === "boolean") { + return String(field); + } else { + return field[ToScriptString](); + } + } + export function IsField(field: any): field is Field { + return (typeof field === "string") + || (typeof field === "number") + || (typeof field === "boolean") + || (field instanceof ObjectField) + || (field instanceof RefField); + } } export type Field = number | string | boolean | ObjectField | RefField; export type Opt = T | undefined; export type FieldWaiting = T extends undefined ? never : Promise; export type FieldResult = Opt | FieldWaiting>; -export const Update = Symbol("Update"); -export const Self = Symbol("Self"); -export const SelfProxy = Symbol("SelfProxy"); -export const WidthSym = Symbol("Width"); -export const HeightSym = Symbol("Height"); - /** * Cast any field to either a List of Docs or undefined if the given field isn't a List of Docs. * If a default value is given, that will be returned instead of undefined. @@ -43,6 +49,9 @@ export function DocListCast(field: FieldResult): Doc[] { return Cast(field, listSpec(Doc), []).filter(d => d instanceof Doc) as Doc[]; } +export const WidthSym = Symbol("Width"); +export const HeightSym = Symbol("Height"); + @Deserializable("doc").withFields(["id"]) export class Doc extends RefField { constructor(id?: FieldId, forceSave?: boolean) { @@ -102,6 +111,10 @@ export class Doc extends RefField { public [WidthSym] = () => NumCast(this[SelfProxy].width); // bcz: is this the right way to access width/height? it didn't work with : this.width public [HeightSym] = () => NumCast(this[SelfProxy].height); + [ToScriptString]() { + return "invalid"; + } + public [HandleUpdate](diff: any) { console.log(diff); const set = diff.$set; diff --git a/src/new_fields/FieldSymbols.ts b/src/new_fields/FieldSymbols.ts new file mode 100644 index 000000000..a436dcf2b --- /dev/null +++ b/src/new_fields/FieldSymbols.ts @@ -0,0 +1,10 @@ + +export const Update = Symbol("Update"); +export const Self = Symbol("Self"); +export const SelfProxy = Symbol("SelfProxy"); +export const HandleUpdate = Symbol("HandleUpdate"); +export const Id = Symbol("Id"); +export const OnUpdate = Symbol("OnUpdate"); +export const Parent = Symbol("Parent"); +export const Copy = Symbol("Copy"); +export const ToScriptString = Symbol("Copy"); \ No newline at end of file diff --git a/src/new_fields/HtmlField.ts b/src/new_fields/HtmlField.ts index d998746bb..f952acff9 100644 --- a/src/new_fields/HtmlField.ts +++ b/src/new_fields/HtmlField.ts @@ -1,6 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString } from "./FieldSymbols"; @Deserializable("html") export class HtmlField extends ObjectField { @@ -15,4 +16,8 @@ export class HtmlField extends ObjectField { [Copy]() { return new HtmlField(this.html); } + + [ToScriptString]() { + return "invalid"; + } } diff --git a/src/new_fields/IconField.ts b/src/new_fields/IconField.ts index 1a928389d..62b2cd254 100644 --- a/src/new_fields/IconField.ts +++ b/src/new_fields/IconField.ts @@ -1,6 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString } from "./FieldSymbols"; @Deserializable("icon") export class IconField extends ObjectField { @@ -15,4 +16,8 @@ export class IconField extends ObjectField { [Copy]() { return new IconField(this.icon); } + + [ToScriptString]() { + return "invalid"; + } } diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 2d75f8a19..4e3b7abe0 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -1,6 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString } from "./FieldSymbols"; import { deepCopy } from "../Utils"; export enum InkTool { @@ -40,4 +41,8 @@ export class InkField extends ObjectField { [Copy]() { return new InkField(deepCopy(this.inkData)); } + + [ToScriptString]() { + return "invalid"; + } } diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index 70e36f911..f1e4c4721 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -1,11 +1,12 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; -import { Field, Update, Self, FieldResult, SelfProxy } from "./Doc"; +import { Field } from "./Doc"; import { setter, getter, deleteProperty, updateFunction } from "./util"; import { serializable, alias, list } from "serializr"; import { observable, action } from "mobx"; -import { ObjectField, OnUpdate, Copy, Parent } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; import { RefField } from "./RefField"; import { ProxyField } from "./Proxy"; +import { Self, Update, Parent, OnUpdate, SelfProxy, ToScriptString, Copy } from "./FieldSymbols"; const listHandlers: any = { /// Mutator methods @@ -225,7 +226,7 @@ type StoredType = T extends RefField ? ProxyField : T; @Deserializable("list") class ListImpl extends ObjectField { - constructor(fields: T[] = []) { + constructor(fields?: T[]) { super(); const list = new Proxy(this, { set: setter, @@ -244,7 +245,9 @@ class ListImpl extends ObjectField { defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, }); this[SelfProxy] = list; - (list as any).push(...fields); + if (fields) { + (list as any).push(...fields); + } return list; } @@ -284,6 +287,11 @@ class ListImpl extends ObjectField { private [Self] = this; private [SelfProxy]: any; + + [ToScriptString]() { + return "invalid"; + // return `new List([${(this as any).map((field => Field.toScriptString(field))}])`; + } } export type List = ListImpl & (T | (T extends RefField ? Promise : never))[]; export const List: { new (fields?: T[]): List } = ListImpl as any; \ No newline at end of file diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts index 51768c6db..5f4a6f8fb 100644 --- a/src/new_fields/ObjectField.ts +++ b/src/new_fields/ObjectField.ts @@ -1,14 +1,13 @@ import { Doc } from "./Doc"; import { RefField } from "./RefField"; - -export const OnUpdate = Symbol("OnUpdate"); -export const Parent = Symbol("Parent"); -export const Copy = Symbol("Copy"); +import { OnUpdate, Parent, Copy, ToScriptString } from "./FieldSymbols"; export abstract class ObjectField { protected [OnUpdate](diff?: any) { } private [Parent]?: RefField | ObjectField; abstract [Copy](): ObjectField; + + abstract [ToScriptString](): string; } export namespace ObjectField { diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts index fd99ae1c0..130ec066e 100644 --- a/src/new_fields/Proxy.ts +++ b/src/new_fields/Proxy.ts @@ -3,8 +3,9 @@ import { FieldWaiting } from "./Doc"; import { primitive, serializable } from "serializr"; import { observable, action } from "mobx"; import { DocServer } from "../client/DocServer"; -import { RefField, Id } from "./RefField"; -import { ObjectField, Copy } from "./ObjectField"; +import { RefField } from "./RefField"; +import { ObjectField } from "./ObjectField"; +import { Id, Copy, ToScriptString } from "./FieldSymbols"; @Deserializable("proxy") export class ProxyField extends ObjectField { @@ -26,6 +27,10 @@ export class ProxyField extends ObjectField { return new ProxyField(this.fieldId); } + [ToScriptString]() { + return "invalid"; + } + @serializable(primitive()) readonly fieldId: string = ""; diff --git a/src/new_fields/RefField.ts b/src/new_fields/RefField.ts index 202c65f21..75ce4287f 100644 --- a/src/new_fields/RefField.ts +++ b/src/new_fields/RefField.ts @@ -1,9 +1,8 @@ import { serializable, primitive, alias } from "serializr"; import { Utils } from "../Utils"; +import { Id, HandleUpdate, ToScriptString } from "./FieldSymbols"; export type FieldId = string; -export const HandleUpdate = Symbol("HandleUpdate"); -export const Id = Symbol("Id"); export abstract class RefField { @serializable(alias("id", primitive())) private __id: FieldId; @@ -15,4 +14,6 @@ export abstract class RefField { } protected [HandleUpdate]?(diff: any): void; + + abstract [ToScriptString](): string; } diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts index eb30e76de..89d077a47 100644 --- a/src/new_fields/RichTextField.ts +++ b/src/new_fields/RichTextField.ts @@ -1,6 +1,7 @@ -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; import { serializable } from "serializr"; import { Deserializable } from "../client/util/SerializationHelper"; +import { Copy, ToScriptString } from "./FieldSymbols"; @Deserializable("RichTextField") export class RichTextField extends ObjectField { @@ -15,4 +16,8 @@ export class RichTextField extends ObjectField { [Copy]() { return new RichTextField(this.Data); } + + [ToScriptString]() { + return "invalid"; + } } \ No newline at end of file diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts index d00a95a16..a6f8f1cc5 100644 --- a/src/new_fields/URLField.ts +++ b/src/new_fields/URLField.ts @@ -1,6 +1,7 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom } from "serializr"; -import { ObjectField, Copy } from "./ObjectField"; +import { ObjectField } from "./ObjectField"; +import { ToScriptString, Copy } from "./FieldSymbols"; function url() { return custom( @@ -13,7 +14,7 @@ function url() { ); } -export class URLField extends ObjectField { +export abstract class URLField extends ObjectField { @serializable(url()) readonly url: URL; @@ -22,6 +23,10 @@ export class URLField extends ObjectField { this.url = url; } + [ToScriptString]() { + return `new ${this.constructor.name}(new URL(${this.url.href}))`; + } + [Copy](): this { return new (this.constructor as any)(this.url); } diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index d94994a07..65a37a0d1 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -1,11 +1,12 @@ import { UndoManager } from "../client/util/UndoManager"; -import { Update, Doc, Field } from "./Doc"; +import { Doc, Field } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField } from "./Proxy"; import { FieldValue } from "./Types"; -import { RefField, Id } from "./RefField"; -import { ObjectField, Parent, OnUpdate } from "./ObjectField"; +import { RefField } from "./RefField"; +import { ObjectField } from "./ObjectField"; import { action } from "mobx"; +import { Parent, OnUpdate, Update, Id } from "./FieldSymbols"; export const setter = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { if (SerializationHelper.IsSerializing()) { -- cgit v1.2.3-70-g09d2 From f62f4d92001e775b7248b7e786de733225e107b5 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 May 2019 11:15:43 -0400 Subject: added switching to low res version based on display size. fixed marqueeing on full size images, fixed bug with kvp pane and image sizing, --- src/client/views/MainView.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 38 ++++++++++++++++++---- 3 files changed, 33 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 9edbba997..6169466bc 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -131,7 +131,7 @@ export class MainView extends React.Component { createNewWorkspace = async (id?: string) => { const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); if (list) { - let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: `WS collection ${list.length + 1}` }); + let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, width: this.pwidth * .7, height: this.pheight, title: `WS collection ${list.length + 1}` }); var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(CurrentUserUtils.UserDocument, 150), CollectionDockingView.makeDocumentConfig(freeformDoc, 600)] }] }; let mainDoc = Docs.DockDocument([CurrentUserUtils.UserDocument, freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }, id); list.push(mainDoc); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index e904358a9..9721bf804 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -434,7 +434,7 @@ export class DockedFrameRenderer extends React.Component { if (this._mainCont.current && this._mainCont.current.children) { let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current.children[0].firstChild as HTMLElement); scale = Utils.GetScreenTransform(this._mainCont.current).scale; - return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / scale); + return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale); } return Transform.Identity(); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 828ac9bc8..0a479cf41 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -17,6 +17,13 @@ import { ImageField } from '../../../new_fields/URLField'; import { List } from '../../../new_fields/List'; import { InkingControl } from '../InkingControl'; import { Doc } from '../../../new_fields/Doc'; +import { faImage } from '@fortawesome/free-solid-svg-icons'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +var path = require('path'); + +library.add(faImage); + export const pageSchema = createSchema({ curPage: "number" @@ -41,7 +48,7 @@ export class ImageBox extends DocComponent(ImageD onLoad = (target: any) => { var h = this._imgRef.current!.naturalHeight; var w = this._imgRef.current!.naturalWidth; - if (this._photoIndex === 0 && (this.props as any).id !== "isExpander") { + if (this._photoIndex === 0 && (this.props as any).id !== "isExpander" && (!this.Document.nativeHeight || !this.Document.nativeWidth)) { Doc.SetOnPrototype(this.Document, "nativeHeight", FieldValue(this.Document.nativeWidth, 0) * h / w); this.Document.height = FieldValue(this.Document.width, 0) * h / w; } @@ -155,14 +162,30 @@ export class ImageBox extends DocComponent(ImageD ); } + @observable _smallImageMissing = false; render() { - let field = this.Document[this.props.fieldKey]; - let paths: string[] = ["http://www.cs.brown.edu/~bcz/face.gif"]; - if (field instanceof ImageField) paths = [field.url.href]; - else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => (p as ImageField).url.href); - let nativeWidth = FieldValue(this.Document.nativeWidth, (this.props.PanelWidth as any) as string ? Number((this.props.PanelWidth as any) as string) : 50); - let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; + let transform = this.props.ScreenToLocalTransform().inverse(); + let pw = Object.keys(this.props.PanelWidth).length === 0 ? this.props.PanelWidth() : (this.props.PanelWidth as any) as string ? Number((this.props.PanelWidth as any) as string) : 50; + var [sptX, sptY] = transform.transformPoint(0, 0); + let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight()); + let w = bptX - sptX; + let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx + let nativeWidth = FieldValue(this.Document.nativeWidth, pw); + let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"]; + if (w > 20) { + if (w < 100 && !this._smallImageMissing) { + let field = this.Document[this.props.fieldKey]; + if (field instanceof ImageField) paths = [field.url.href.replace(path.extname(field.url.href), "_s" + path.extname(field.url.href))]; + else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => + (p as ImageField).url.href.replace(path.extname((p as ImageField).url.href), "_s" + path.extname((p as ImageField).url.href))); + } else { + let field = this.Document[this.props.fieldKey]; + if (field instanceof ImageField) paths = [field.url.href]; + else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => (p as ImageField).url.href); + } + } + let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; return (
(ImageD style={{ objectFit: (this._photoIndex === 0 ? undefined : "contain") }} width={nativeWidth} ref={this._imgRef} + onError={action(() => this._smallImageMissing = true)} onLoad={this.onLoad} /> {paths.length > 1 ? this.dots(paths) : (null)} {this.lightbox(paths)} -- cgit v1.2.3-70-g09d2 From baa57bae05df83c37e4573b7afb92948fc6e910b Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 May 2019 11:24:54 -0400 Subject: using all image sizes now. --- src/client/views/nodes/ImageBox.tsx | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0a479cf41..b4aae3646 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -163,6 +163,9 @@ export class ImageBox extends DocComponent(ImageD } @observable _smallImageMissing = false; + @observable _mediumImageMissing = false; + @observable _largeImageMissing = false; + _curImageSize = ""; render() { let transform = this.props.ScreenToLocalTransform().inverse(); let pw = Object.keys(this.props.PanelWidth).length === 0 ? this.props.PanelWidth() : (this.props.PanelWidth as any) as string ? Number((this.props.PanelWidth as any) as string) : 50; @@ -175,14 +178,23 @@ export class ImageBox extends DocComponent(ImageD let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"]; if (w > 20) { if (w < 100 && !this._smallImageMissing) { + this._curImageSize = "small"; let field = this.Document[this.props.fieldKey]; if (field instanceof ImageField) paths = [field.url.href.replace(path.extname(field.url.href), "_s" + path.extname(field.url.href))]; else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => (p as ImageField).url.href.replace(path.extname((p as ImageField).url.href), "_s" + path.extname((p as ImageField).url.href))); - } else { + } else if (w < 600 && !this._mediumImageMissing) { + this._curImageSize = "medium"; let field = this.Document[this.props.fieldKey]; - if (field instanceof ImageField) paths = [field.url.href]; - else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => (p as ImageField).url.href); + if (field instanceof ImageField) paths = [field.url.href.replace(path.extname(field.url.href), "_m" + path.extname(field.url.href))]; + else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => + (p as ImageField).url.href.replace(path.extname((p as ImageField).url.href), "_m" + path.extname((p as ImageField).url.href))); + } else if (!this._largeImageMissing) { + this._curImageSize = "large"; + let field = this.Document[this.props.fieldKey]; + if (field instanceof ImageField) paths = [field.url.href.replace(path.extname(field.url.href), "_l" + path.extname(field.url.href))]; + else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => + (p as ImageField).url.href.replace(path.extname((p as ImageField).url.href), "_l" + path.extname((p as ImageField).url.href))); } } let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; @@ -194,7 +206,11 @@ export class ImageBox extends DocComponent(ImageD style={{ objectFit: (this._photoIndex === 0 ? undefined : "contain") }} width={nativeWidth} ref={this._imgRef} - onError={action(() => this._smallImageMissing = true)} + onError={action(() => { + if (this._curImageSize === "small") this._smallImageMissing = true; + if (this._curImageSize === "medium") this._mediumImageMissing = true; + if (this._curImageSize === "large") this._largeImageMissing = true; + })} onLoad={this.onLoad} /> {paths.length > 1 ? this.dots(paths) : (null)} {this.lightbox(paths)} -- cgit v1.2.3-70-g09d2 From e5d71fc1362c77f076c10187625c74fe294669aa Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 May 2019 12:20:57 -0400 Subject: fixes to caching. lower quality Summary images. --- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 57 +++++++++++----------- 2 files changed, 30 insertions(+), 29 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 2029b91e5..6ea230aab 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -257,7 +257,7 @@ export class MarqueeView extends React.Component if (e.key === "s" || e.key === "p") { - htmlToImage.toPng(this._mainCont.current!, { width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, quality: 1 }).then((dataUrl) => { + htmlToImage.toPng(this._mainCont.current!, { width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, quality: 0.2 }).then((dataUrl) => { selected.map(d => { this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index b4aae3646..29a99e53c 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -162,13 +162,25 @@ export class ImageBox extends DocComponent(ImageD ); } - @observable _smallImageMissing = false; - @observable _mediumImageMissing = false; - @observable _largeImageMissing = false; - _curImageSize = ""; + choosePath(url: URL) { + if (url.protocol === "data") + return url.href; + let ext = path.extname(url.href); + return url.href.replace(ext, this._curSuffix + ext); + } + + @observable _smallRetryCount = 1; + @observable _mediumRetryCount = 1; + @observable _largeRetryCount = 1; + @action retryPath = () => { + if (this._curSuffix === "_s") this._smallRetryCount++; + if (this._curSuffix === "_m") this._mediumRetryCount++; + if (this._curSuffix === "_l") this._largeRetryCount++; + } + _curSuffix = ""; render() { let transform = this.props.ScreenToLocalTransform().inverse(); - let pw = Object.keys(this.props.PanelWidth).length === 0 ? this.props.PanelWidth() : (this.props.PanelWidth as any) as string ? Number((this.props.PanelWidth as any) as string) : 50; + let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50; var [sptX, sptY] = transform.transformPoint(0, 0); let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight()); let w = bptX - sptX; @@ -176,40 +188,29 @@ export class ImageBox extends DocComponent(ImageD let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx let nativeWidth = FieldValue(this.Document.nativeWidth, pw); let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"]; + this._curSuffix = ""; if (w > 20) { - if (w < 100 && !this._smallImageMissing) { - this._curImageSize = "small"; - let field = this.Document[this.props.fieldKey]; - if (field instanceof ImageField) paths = [field.url.href.replace(path.extname(field.url.href), "_s" + path.extname(field.url.href))]; - else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => - (p as ImageField).url.href.replace(path.extname((p as ImageField).url.href), "_s" + path.extname((p as ImageField).url.href))); - } else if (w < 600 && !this._mediumImageMissing) { - this._curImageSize = "medium"; - let field = this.Document[this.props.fieldKey]; - if (field instanceof ImageField) paths = [field.url.href.replace(path.extname(field.url.href), "_m" + path.extname(field.url.href))]; - else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => - (p as ImageField).url.href.replace(path.extname((p as ImageField).url.href), "_m" + path.extname((p as ImageField).url.href))); - } else if (!this._largeImageMissing) { - this._curImageSize = "large"; - let field = this.Document[this.props.fieldKey]; - if (field instanceof ImageField) paths = [field.url.href.replace(path.extname(field.url.href), "_l" + path.extname(field.url.href))]; - else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => - (p as ImageField).url.href.replace(path.extname((p as ImageField).url.href), "_l" + path.extname((p as ImageField).url.href))); - } + let field = this.Document[this.props.fieldKey]; + if (w < 100) this._curSuffix = "_s"; + else if (w < 600) this._curSuffix = "_m"; + else this._curSuffix = "_l"; + if (field instanceof ImageField) paths = [this.choosePath(field.url)]; + else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => this.choosePath((p as ImageField).url)); } let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; return (
- { - if (this._curImageSize === "small") this._smallImageMissing = true; - if (this._curImageSize === "medium") this._mediumImageMissing = true; - if (this._curImageSize === "large") this._largeImageMissing = true; + let timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount; + setTimeout(this.retryPath, Math.min(10000, timeout * 5)); })} onLoad={this.onLoad} /> {paths.length > 1 ? this.dots(paths) : (null)} -- cgit v1.2.3-70-g09d2 From 850ac067fb4e62f91a6eee8df40fe95eca3a3326 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 May 2019 13:15:16 -0400 Subject: changed so that cat image works. --- src/client/views/nodes/ImageBox.tsx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 29a99e53c..1bd1b80a7 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -177,6 +177,11 @@ export class ImageBox extends DocComponent(ImageD if (this._curSuffix === "_m") this._mediumRetryCount++; if (this._curSuffix === "_l") this._largeRetryCount++; } + @action onError = () => { + let timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount; + if (timeout < 10) + setTimeout(this.retryPath, Math.min(10000, timeout * 5)); + } _curSuffix = ""; render() { let transform = this.props.ScreenToLocalTransform().inverse(); @@ -191,9 +196,9 @@ export class ImageBox extends DocComponent(ImageD this._curSuffix = ""; if (w > 20) { let field = this.Document[this.props.fieldKey]; - if (w < 100) this._curSuffix = "_s"; - else if (w < 600) this._curSuffix = "_m"; - else this._curSuffix = "_l"; + if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; + else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m"; + else if (this._largeRetryCount < 10) this._curSuffix = "_l"; if (field instanceof ImageField) paths = [this.choosePath(field.url)]; else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => this.choosePath((p as ImageField).url)); } @@ -205,16 +210,13 @@ export class ImageBox extends DocComponent(ImageD { - let timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount; - setTimeout(this.retryPath, Math.min(10000, timeout * 5)); - })} + onError={this.onError} onLoad={this.onLoad} /> {paths.length > 1 ? this.dots(paths) : (null)} - {this.lightbox(paths)} + {/* {this.lightbox(paths)} */}
); } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 9c8cd369019f1da21c75c07abecdbe3cf5da4cfe Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 May 2019 13:25:06 -0400 Subject: only apply suffixes to urls that are on our server... --- src/client/views/nodes/ImageBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 1bd1b80a7..a2291c7cf 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -163,7 +163,7 @@ export class ImageBox extends DocComponent(ImageD } choosePath(url: URL) { - if (url.protocol === "data") + if (url.protocol === "data" || url.href.indexOf(window.location.origin) === -1) return url.href; let ext = path.extname(url.href); return url.href.replace(ext, this._curSuffix + ext); -- cgit v1.2.3-70-g09d2 From e02e8bee7ee36490b83edb0a416978216b0f4a17 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 May 2019 15:46:21 -0400 Subject: hooking up image data url stuff. --- src/client/views/SearchBox.tsx | 17 +++++++++++++++++ src/client/views/nodes/PDFBox.tsx | 10 +++++++--- src/server/index.ts | 8 +++++--- 3 files changed, 29 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 8efd8d266..0ec1a6758 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -20,6 +20,7 @@ import { Id } from '../../new_fields/FieldSymbols'; import { DocumentManager } from '../util/DocumentManager'; import { SetupDrag } from '../util/DragManager'; import { Docs } from '../documents/Documents'; +import { RouteStore } from '../../server/RouteStore'; library.add(faSearch); library.add(faObjectGroup); @@ -70,6 +71,22 @@ export class SearchBox extends React.Component { } return docs; } + public static async convertDataUri(imageUri: string, returnedFilename: string) { + try { + let posting = DocServer.prepend(RouteStore.dataUriToImage); + const returnedUri = await rp.post(posting, { + body: { + uri: imageUri, + name: returnedFilename + }, + json: true, + }); + return returnedUri; + + } catch (e) { + console.log(e); + } + } @action handleClickFilter = (e: Event): void => { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index e71ac4924..1017f5235 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -21,6 +21,8 @@ import { positionSchema } from "./DocumentView"; import { pageSchema } from "./ImageBox"; import { ImageField, PdfField } from "../../../new_fields/URLField"; import { InkingControl } from "../InkingControl"; +import { SearchBox } from "../SearchBox"; +import { Id } from "../../../new_fields/FieldSymbols"; /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, @@ -250,9 +252,11 @@ export class PDFBox extends DocComponent(PdfDocumen let nheight = FieldValue(this.Document.nativeHeight, 0); htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 1 }) .then(action((dataUrl: string) => { - this.props.Document.thumbnail = new ImageField(new URL(dataUrl)); - this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1); - this._renderAsSvg = true; + SearchBox.convertDataUri(dataUrl, this.Document[Id] + "_" + this.curPage).then((returnedFilename) => { + this.props.Document.thumbnail = new ImageField(new URL(dataUrl)); + this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1); + this._renderAsSvg = true; + }) })) .catch(function (error: any) { console.error('oops, something went wrong!', error); diff --git a/src/server/index.ts b/src/server/index.ts index a12751fe3..6843afbe4 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -114,6 +114,8 @@ function addSecureRoute(method: Method, app.use(express.static(__dirname + RouteStore.public)); app.use(RouteStore.images, express.static(__dirname + RouteStore.public)); +app.use(express.json()); + app.get("/pull", (req, res) => exec('"C:\\Program Files\\Git\\git-bash.exe" -c "git pull"', (err, stdout, stderr) => { if (err) { @@ -220,10 +222,10 @@ addSecureRoute( addSecureRoute( Method.POST, (user, res, req) => { - const uri = req.query.uri; - const filename = req.query.name; + const uri = req.body.uri; + const filename = req.body.name; if (!uri || !filename) { - res.status(400).send("incorrect parameters specified"); + res.status(401).send("incorrect parameters specified"); return; } imageDataUri.outputFile(uri, uploadDir + filename).then((savedName: string) => { -- cgit v1.2.3-70-g09d2 From 059faf25a0f8ba80e1d2853dcefa1a70df4cbb6a Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 May 2019 17:10:21 -0400 Subject: fixed icons for pdfs. fixed activeItem issue for golden layout. --- src/client/goldenLayout.js | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 1 + src/client/views/nodes/PDFBox.tsx | 58 +++++++++++----------- 3 files changed, 31 insertions(+), 30 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js index ab2bcefed..54c9c6068 100644 --- a/src/client/goldenLayout.js +++ b/src/client/goldenLayout.js @@ -4466,7 +4466,7 @@ } if (this.contentItems.length > 0) { - initialItem = this.contentItems[this.config.activeItemIndex || 0]; + initialItem = this.contentItems[Math.min(this.contentItems.length - 1, this.config.activeItemIndex || 0)]; if (!initialItem) { throw new Error('Configured activeItemIndex out of bounds'); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 5bff08280..fa2b09ba7 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -189,6 +189,7 @@ export class CollectionFreeFormDocumentView extends DocComponent(PdfDocumen @computed private get thumbnailPage() { return NumCast(this.props.Document.thumbnailPage, -1); } componentDidMount() { - let wasSelected = false; + let wasSelected = this.props.isSelected(); this._reactionDisposer = reaction( - () => this.props.isSelected(), + () => [this.props.isSelected(), this.curPage], () => { - if (this.curPage > 0 && this.curPage !== this.thumbnailPage && wasSelected && !this.props.isSelected()) { + if (this.curPage > 0 && !this.props.isTopMost && this.curPage !== this.thumbnailPage && wasSelected && !this.props.isSelected()) { this.saveThumbnail(); } wasSelected = this._interactive = this.props.isSelected(); @@ -246,16 +245,19 @@ export class PDFBox extends DocComponent(PdfDocumen @action saveThumbnail = () => { + this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1); this._renderAsSvg = false; setTimeout(() => { let nwidth = FieldValue(this.Document.nativeWidth, 0); let nheight = FieldValue(this.Document.nativeHeight, 0); - htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 1 }) + htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 0.8 }) .then(action((dataUrl: string) => { - SearchBox.convertDataUri(dataUrl, this.Document[Id] + "_" + this.curPage).then((returnedFilename) => { - this.props.Document.thumbnail = new ImageField(new URL(dataUrl)); - this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1); - this._renderAsSvg = true; + SearchBox.convertDataUri(dataUrl, "icon" + this.Document[Id] + "_" + this.curPage).then((returnedFilename) => { + if (returnedFilename) { + let url = DocServer.prepend(returnedFilename); + this.props.Document.thumbnail = new ImageField(new URL(url)); + } + runInAction(() => this._renderAsSvg = true); }) })) .catch(function (error: any) { @@ -292,7 +294,6 @@ export class PDFBox extends DocComponent(PdfDocumen } @computed get pdfContent() { - trace(); let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField); if (!pdfUrl) { return

No pdf url to render

; @@ -309,7 +310,7 @@ export class PDFBox extends DocComponent(PdfDocumen ; let xf = (this.Document.nativeHeight || 0) / this.renderHeight; return
- + {body}
; @@ -317,26 +318,25 @@ export class PDFBox extends DocComponent(PdfDocumen @computed get pdfRenderer() { - let proxy = this._loaded ? (null) : this.imageProxyRenderer; let pdfUrl = Cast(this.props.Document[this.props.fieldKey], PdfField); - if ((!this._interactive && proxy) || !pdfUrl) { + let proxy = this.imageProxyRenderer; + if ((!this._interactive && proxy && (!this.props.ContainingCollectionView || !this.props.ContainingCollectionView.props.isTopMost)) || !pdfUrl) { return proxy; } return [ this._pageInfo.area.filter(() => this._pageInfo.area).map((element: any) => element), this._currAnno.map((element: any) => element), - this.pdfContent, - proxy + this.pdfContent ]; } @computed get imageProxyRenderer() { let thumbField = this.props.Document.thumbnail; - if (thumbField) { - let path = this.thumbnailPage !== this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" : + if (thumbField && this._renderAsSvg) { + let path = // this.thumbnailPage !== this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" : thumbField instanceof ImageField ? thumbField.url.href : "http://cs.brown.edu/people/bcz/prairie.jpg"; - return ; + return ; } return (null); } -- cgit v1.2.3-70-g09d2 From e5c9ba12e9a50a688e8c1554b525c87b1efbafb8 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 May 2019 17:23:09 -0400 Subject: added s/m/l icons for pdf rendering. --- src/client/views/nodes/ImageBox.tsx | 1 - src/client/views/nodes/PDFBox.tsx | 43 +++++++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index a2291c7cf..8156ec872 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -19,7 +19,6 @@ import { InkingControl } from '../InkingControl'; import { Doc } from '../../../new_fields/Doc'; import { faImage } from '@fortawesome/free-solid-svg-icons'; import { library } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; var path = require('path'); library.add(faImage); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index d1b9098b0..2a59eb7e5 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -21,6 +21,7 @@ import { positionSchema } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; +var path = require('path'); import React = require("react"); /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx @@ -330,20 +331,54 @@ export class PDFBox extends DocComponent(PdfDocumen ]; } + choosePath(url: URL) { + if (url.protocol === "data" || url.href.indexOf(window.location.origin) === -1) + return url.href; + let ext = path.extname(url.href); + return url.href.replace(ext, this._curSuffix + ext); + } + @observable _smallRetryCount = 1; + @observable _mediumRetryCount = 1; + @observable _largeRetryCount = 1; + @action retryPath = () => { + if (this._curSuffix === "_s") this._smallRetryCount++; + if (this._curSuffix === "_m") this._mediumRetryCount++; + if (this._curSuffix === "_l") this._largeRetryCount++; + } + @action onError = () => { + let timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount; + if (timeout < 10) + setTimeout(this.retryPath, Math.min(10000, timeout * 5)); + } + _curSuffix = ""; + @computed get imageProxyRenderer() { let thumbField = this.props.Document.thumbnail; if (thumbField && this._renderAsSvg) { - let path = // this.thumbnailPage !== this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" : - thumbField instanceof ImageField ? thumbField.url.href : "http://cs.brown.edu/people/bcz/prairie.jpg"; - return ; + + let transform = this.props.ScreenToLocalTransform().inverse(); + let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50; + var [sptX, sptY] = transform.transformPoint(0, 0); + let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight()); + let w = bptX - sptX; + + let path = thumbField instanceof ImageField ? thumbField.url.href : "http://cs.brown.edu/people/bcz/prairie.jpg"; + this._curSuffix = ""; + if (w > 20) { + let field = thumbField; + if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; + else if (w < 400 && this._mediumRetryCount < 10) this._curSuffix = "_m"; + else if (this._largeRetryCount < 10) this._curSuffix = "_l"; + if (field instanceof ImageField) path = this.choosePath(field.url); + } + return ; } return (null); } @action onKeyDown = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = true); @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false); render() { - trace(); let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); return (
-- cgit v1.2.3-70-g09d2 From 70930405f8bdf43c05a77cb3dcbdadcbd3c9ab70 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 20 May 2019 19:10:10 -0400 Subject: PDF and Image test Context work --- .../views/collections/CollectionDockingView.tsx | 3 ++- .../views/collections/ParentDocumentSelector.scss | 10 ++++++++ .../views/collections/ParentDocumentSelector.tsx | 24 ++++++++++++++----- src/client/views/nodes/ImageBox.tsx | 28 +++++++++++----------- src/client/views/nodes/PDFBox.tsx | 26 ++++++++++---------- src/new_fields/Doc.ts | 13 ++++++---- 6 files changed, 65 insertions(+), 39 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 9721bf804..180a8be46 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -332,7 +332,8 @@ export class CollectionDockingView extends React.Component0
`); tab.element.append(counter); let upDiv = document.createElement("span"); - ReactDOM.render(, upDiv); + const stack = tab.contentItem.parent; + ReactDOM.render( CollectionDockingView.Instance.AddTab(stack, doc)} />, upDiv); tab.reactComponents = [upDiv]; tab.element.append(upDiv); counter.DashDocId = tab.contentItem.config.props.documentId; diff --git a/src/client/views/collections/ParentDocumentSelector.scss b/src/client/views/collections/ParentDocumentSelector.scss index f3c605f3e..1ab12bb72 100644 --- a/src/client/views/collections/ParentDocumentSelector.scss +++ b/src/client/views/collections/ParentDocumentSelector.scss @@ -5,4 +5,14 @@ box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); min-width: 150px; color: black; + + hr { + height: 1px; + margin: 0px; + background-color: gray; + border-top: 0px; + border-bottom: 0px; + border-right: 0px; + border-left: 0px; + } } \ No newline at end of file diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 4d07c31a7..65ae7f9ec 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -7,32 +7,44 @@ import { Id } from "../../../new_fields/FieldSymbols"; import { SearchUtil } from "../../util/SearchUtil"; import { CollectionDockingView } from "./CollectionDockingView"; +type SelectorProps = { Document: Doc, addDocTab(doc: Doc, location: string): void }; @observer -export class SelectorContextMenu extends React.Component<{ Document: Doc }> { +export class SelectorContextMenu extends React.Component { @observable private _docs: Doc[] = []; + @observable private _otherDocs: Doc[] = []; - constructor(props: { Document: Doc }) { + constructor(props: SelectorProps) { super(props); this.fetchDocuments(); } async fetchDocuments() { + let aliases = (await SearchUtil.GetAliasesOfDocument(this.props.Document)).filter(doc => doc !== this.props.Document); const docs = await SearchUtil.Search(`data_l:"${this.props.Document[Id]}"`, true); - runInAction(() => this._docs = docs); + const otherDocs: Set = new Set; + const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search(`data_l:"${doc[Id]}"`, true))); + allDocs.forEach(docs => docs.forEach(doc => otherDocs.add(doc))); + docs.forEach(doc => otherDocs.delete(doc)); + runInAction(() => { + this._docs = docs.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)); + this._otherDocs = Array.from(otherDocs).filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)); + }); } render() { return ( <> - {this._docs.map(doc =>

CollectionDockingView.Instance.AddRightSplit(doc)}>{doc.title}

)} + {this._docs.map(doc =>

this.props.addDocTab(Doc.IsPrototype(doc) ? Doc.MakeDelegate(doc) : doc, "inTab")}>{doc.title}

)} + {this._otherDocs.length ?
: null} + {this._otherDocs.map(doc =>

this.props.addDocTab(Doc.IsPrototype(doc) ? Doc.MakeDelegate(doc) : doc, "inTab")}>{doc.title}

)} ); } } @observer -export class ParentDocSelector extends React.Component<{ Document: Doc }> { +export class ParentDocSelector extends React.Component { @observable hover = false; @action @@ -50,7 +62,7 @@ export class ParentDocSelector extends React.Component<{ Document: Doc }> { if (this.hover) { flyout = (
- +
); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 8156ec872..e022793eb 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -181,26 +181,26 @@ export class ImageBox extends DocComponent(ImageD if (timeout < 10) setTimeout(this.retryPath, Math.min(10000, timeout * 5)); } - _curSuffix = ""; + _curSuffix = "_m"; render() { - let transform = this.props.ScreenToLocalTransform().inverse(); + // let transform = this.props.ScreenToLocalTransform().inverse(); let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50; - var [sptX, sptY] = transform.transformPoint(0, 0); - let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight()); - let w = bptX - sptX; + // var [sptX, sptY] = transform.transformPoint(0, 0); + // let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight()); + // let w = bptX - sptX; let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx let nativeWidth = FieldValue(this.Document.nativeWidth, pw); let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"]; - this._curSuffix = ""; - if (w > 20) { - let field = this.Document[this.props.fieldKey]; - if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; - else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m"; - else if (this._largeRetryCount < 10) this._curSuffix = "_l"; - if (field instanceof ImageField) paths = [this.choosePath(field.url)]; - else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => this.choosePath((p as ImageField).url)); - } + // this._curSuffix = ""; + // if (w > 20) { + let field = this.Document[this.props.fieldKey]; + // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; + // else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m"; + // else if (this._largeRetryCount < 10) this._curSuffix = "_l"; + if (field instanceof ImageField) paths = [this.choosePath(field.url)]; + else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => this.choosePath((p as ImageField).url)); + // } let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; return (
(PdfDocumen if (timeout < 10) setTimeout(this.retryPath, Math.min(10000, timeout * 5)); } - _curSuffix = ""; + _curSuffix = "_m"; @computed get imageProxyRenderer() { let thumbField = this.props.Document.thumbnail; if (thumbField && this._renderAsSvg) { - let transform = this.props.ScreenToLocalTransform().inverse(); + // let transform = this.props.ScreenToLocalTransform().inverse(); let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50; - var [sptX, sptY] = transform.transformPoint(0, 0); - let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight()); - let w = bptX - sptX; + // var [sptX, sptY] = transform.transformPoint(0, 0); + // let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight()); + // let w = bptX - sptX; let path = thumbField instanceof ImageField ? thumbField.url.href : "http://cs.brown.edu/people/bcz/prairie.jpg"; - this._curSuffix = ""; - if (w > 20) { - let field = thumbField; - if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; - else if (w < 400 && this._mediumRetryCount < 10) this._curSuffix = "_m"; - else if (this._largeRetryCount < 10) this._curSuffix = "_l"; - if (field instanceof ImageField) path = this.choosePath(field.url); - } + // this._curSuffix = ""; + // if (w > 20) { + let field = thumbField; + // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; + // else if (w < 400 && this._mediumRetryCount < 10) this._curSuffix = "_m"; + // else if (this._largeRetryCount < 10) this._curSuffix = "_l"; + if (field instanceof ImageField) path = this.choosePath(field.url); + // } return ; } return (null); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index f4514c33e..92d3c140a 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -149,6 +149,9 @@ export namespace Doc { export function GetT(doc: Doc, key: string, ctor: ToConstructor, ignoreProto: boolean = false): FieldResult { return Cast(Get(doc, key, ignoreProto), ctor) as FieldResult; } + export function IsPrototype(doc: Doc) { + return GetT(doc, "isPrototype", "boolean", true); + } export async function SetOnPrototype(doc: Doc, key: string, value: Field) { const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : doc; @@ -180,11 +183,11 @@ export namespace Doc { // compare whether documents or their protos match export function AreProtosEqual(doc: Doc, other: Doc) { - let r = (doc[Id] === other[Id]); - let r2 = (doc.proto && doc.proto.Id === other[Id]); - let r3 = (other.proto && other.proto.Id === doc[Id]); - let r4 = (doc.proto && other.proto && doc.proto[Id] === other.proto[Id]); - return r || r2 || r3 || r4 ? true : false; + let r = (doc === other); + let r2 = (doc.proto === other); + let r3 = (other.proto === doc); + let r4 = (doc.proto === other.proto); + return r || r2 || r3 || r4; } // gets the document's prototype or returns the document if it is a prototype -- cgit v1.2.3-70-g09d2 From 060455feec89c94073636f612ccca54a0aaabb90 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 May 2019 21:29:17 -0400 Subject: fixed a few things for Firefox - dragging images, typing spaces, scrool speed. and focusing proeprly with zoomBasis. --- .vscode/launch.json | 9 +++++++++ .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 9 +++------ src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 3 +++ src/client/views/nodes/FormattedTextBox.tsx | 4 ++-- 4 files changed, 17 insertions(+), 8 deletions(-) (limited to 'src/client/views/nodes') diff --git a/.vscode/launch.json b/.vscode/launch.json index d245be2ad..3b6549767 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,6 +13,15 @@ "url": "http://localhost:1050/login", "webRoot": "${workspaceFolder}", }, + { + "type": "firefox", + "request": "launch", + "name": "Launch Firefox against localhost", + "sourceMaps": "client", + "reAttach": true, + "url": "http://localhost:1050/login", + "webRoot": "${workspaceFolder}", + }, { "type": "chrome", "request": "launch", diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ee6f4821f..3ec7184d2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -183,7 +183,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return; } e.stopPropagation(); - const coefficient = 1000; + const coefficient = 100; if (e.ctrlKey) { let deltaScale = (1 - (e.deltaY / coefficient)); @@ -215,7 +215,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action setPan(panX: number, panY: number) { - this.panDisposer && clearTimeout(this.panDisposer); this.props.Document.panTransformType = "None"; var scale = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX)); @@ -243,7 +242,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { doc.zIndex = docs.length + 1; } - panDisposer?: NodeJS.Timeout; focusDocument = (doc: Doc) => { const panX = this.Document.panX; const panY = this.Document.panY; @@ -265,15 +263,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } } SelectionManager.DeselectAll(); - const newPanX = NumCast(doc.x) + NumCast(doc.width) / 2; - const newPanY = NumCast(doc.y) + NumCast(doc.height) / 2; + const newPanX = NumCast(doc.x) + NumCast(doc.width) / NumCast(doc.zoomBasis, 1) / 2; + const newPanY = NumCast(doc.y) + NumCast(doc.height) / NumCast(doc.zoomBasis, 1) / 2; const newState = HistoryUtil.getState(); newState.initializers[id] = { panX: newPanX, panY: newPanY }; HistoryUtil.pushState(newState); this.setPan(newPanX, newPanY); this.props.Document.panTransformType = "Ease"; this.props.focus(this.props.Document); - this.panDisposer = setTimeout(() => this.props.Document.panTransformType = "None", 2000); // wait 3 seconds, then reset to false } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index fa2b09ba7..7c3180496 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -177,6 +177,9 @@ export class CollectionFreeFormDocumentView extends DocComponent { document.removeEventListener("pointerup", this.onPointerUp); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index d15813f9a..5afef221c 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -366,7 +366,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe style={{ pointerEvents: interactive ? "all" : "none", }} - onKeyDown={this.onKeyPress} + // onKeyDown={this.onKeyPress} onKeyPress={this.onKeyPress} onFocus={this.onFocused} onClick={this.onClick} @@ -378,7 +378,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe // tfs: do we need this event handler onWheel={this.onPointerWheel} > -
+
); } -- cgit v1.2.3-70-g09d2 From 505676028698f22e46854fdd8ea25ea3118b5d6f Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 May 2019 22:31:37 -0400 Subject: fixed annotation pages for videos --- src/Utils.ts | 13 +++++++++++++ src/client/views/InkingCanvas.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 6 ++++-- 4 files changed, 19 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/Utils.ts b/src/Utils.ts index 24878a368..611c61135 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -39,6 +39,19 @@ export class Utils { document.body.removeChild(textArea); } + public static GetClipboardText(): string { + var textArea = document.createElement("textarea"); + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { document.execCommand('paste'); } catch (err) { } + + const val = textArea.value; + document.body.removeChild(textArea); + return val; + } + public static loggingEnabled: Boolean = false; public static logFilter: number | undefined = undefined; private static log(prefix: string, messageName: string, message: any, receiving: boolean) { diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index afe3e3ecb..42ab08001 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -146,7 +146,7 @@ export class InkingCanvas extends React.Component { get drawnPaths() { let curPage = NumCast(this.props.Document.curPage, -1); let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => { - if (strokeData.page === -1 || strokeData.page === curPage) { + if (strokeData.page === -1 || Math.round(strokeData.page) === Math.round(curPage)) { paths.push( { if (!(doc instanceof Doc)) return prev; var page = NumCast(doc.page, -1); - if (page === curPage || page === -1) { + if (Math.round(page) === Math.round(curPage) || page === -1) { let minim = BoolCast(doc.isMinimized, false); if (minim === undefined || !minim) { prev.push(); diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 81c429a02..6ae55d151 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -52,7 +52,7 @@ export class VideoBox extends DocComponent(VideoD @action public Play() { this.Playing = true; if (this.player) this.player.play(); - if (!this._playTimer) this._playTimer = setInterval(this.updateTimecode, 1000); + if (!this._playTimer) this._playTimer = setInterval(this.updateTimecode, 500); } @action public Pause() { @@ -70,7 +70,9 @@ export class VideoBox extends DocComponent(VideoD } @action - updateTimecode = () => this.player && (this.props.Document.curPage = this.player.currentTime) + updateTimecode = () => { + this.player && (this.props.Document.curPage = this.player.currentTime); + } componentDidMount() { if (this.props.setVideoBox) this.props.setVideoBox(this); -- cgit v1.2.3-70-g09d2 From 3abf1b817a5ed0e2bcacaa08f4a15a9193794a3a Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 21 May 2019 08:22:24 -0400 Subject: Fixed performance problems --- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 6 +++--- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 97e610e13..31864f357 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,5 +1,5 @@ import * as htmlToImage from "html-to-image"; -import { action, computed, observable } from "mobx"; +import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { Docs } from "../../../documents/Documents"; import { SelectionManager } from "../../../util/SelectionManager"; @@ -344,10 +344,10 @@ export class MarqueeView extends React.Component } render() { - let p = this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY); + let p: [number, number] = this._visible ? this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY) : [0, 0]; return
- {!this._visible ? null : this.marqueeDiv} + {this._visible ? this.marqueeDiv : null}
{this.props.children}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 7c3180496..bf0c272e3 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,4 +1,4 @@ -import { action, computed, IReactionDisposer, reaction } from "mobx"; +import { action, computed, IReactionDisposer, reaction, trace } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; @@ -211,7 +211,7 @@ export class CollectionFreeFormDocumentView extends DocComponent Doc.GetProto(doc)) + let expandedProtoDocs = expandedDocs.map(doc => Doc.GetProto(doc)); let maxLocation = StrCast(this.props.Document.maximizeLocation, "inPlace"); let getDispDoc = (target: Doc) => Object.getOwnPropertyNames(target).indexOf("isPrototype") === -1 ? target : Doc.MakeDelegate(target); if (altKey) { @@ -286,7 +286,9 @@ export class CollectionFreeFormDocumentView extends DocComponent Date: Tue, 21 May 2019 09:34:10 -0400 Subject: Fixed speed again? --- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 10 +++++----- src/client/views/nodes/DocumentContentsView.tsx | 5 +++-- src/client/views/nodes/ImageBox.tsx | 2 +- src/new_fields/Doc.ts | 1 - 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index bf0c272e3..aaaa6a9c5 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -266,15 +266,15 @@ export class CollectionFreeFormDocumentView extends DocComponent 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1; const screenWidth = Math.min(50 * NumCast(this.props.Document.nativeWidth, 0), 1800); let fadeUp = .75 * screenWidth; let fadeDown = (maximizedDoc ? .0075 : .075) * screenWidth; - zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0.1, Math.min(1, 2 - (w < fadeDown ? Math.sqrt(Math.sqrt(fadeDown / w)) : w / fadeUp))) : 1; + // zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0.1, Math.min(1, 2 - (w < fadeDown ? Math.sqrt(Math.sqrt(fadeDown / w)) : w / fadeUp))) : 1; return (
Date: Tue, 21 May 2019 11:44:51 -0400 Subject: Fixed various scripting things --- src/client/util/type_decls.d | 33 ++++++++++++++++------ .../views/collections/CollectionSchemaView.tsx | 10 +++---- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 8 ++---- src/debug/Viewer.tsx | 2 +- src/new_fields/Doc.ts | 7 +++-- src/new_fields/URLField.ts | 9 ++++-- 7 files changed, 46 insertions(+), 25 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d index 51114d0e2..557f6f574 100644 --- a/src/client/util/type_decls.d +++ b/src/client/util/type_decls.d @@ -140,33 +140,50 @@ declare const ToScriptString: unique symbol; declare abstract class RefField { readonly [Id]: FieldId; - constructor(id?: FieldId); - protected [HandleUpdate]?(diff: any): void; + constructor(); + // protected [HandleUpdate]?(diff: any): void; - abstract [ToScriptString](): string; + // abstract [ToScriptString](): string; } declare abstract class ObjectField { protected [OnUpdate](diff?: any): void; private [Parent]?: RefField | ObjectField; - abstract [Copy](): ObjectField; + // abstract [Copy](): ObjectField; - abstract [ToScriptString](): string; + // abstract [ToScriptString](): string; } + +declare abstract class URLField extends ObjectField { + readonly url: URL; + + constructor(url: string); + constructor(url: URL); +} + +declare class AudioField extends URLField { } +declare class VideoField extends URLField { } +declare class ImageField extends URLField { } +declare class WebField extends URLField { } +declare class PdfField extends URLField { } + declare type FieldId = string; declare type Field = number | string | boolean | ObjectField | RefField; declare type Opt = T | undefined; declare class Doc extends RefField { + constructor(); + [key: string]: Field | undefined; - [ToScriptString](): string; + // [ToScriptString](): string; } declare class ListImpl extends ObjectField { + constructor(fields?: T[]); [index: number]: T | (T extends RefField ? Promise : never); - [ToScriptString](): string; - [Copy](): ObjectField; + // [ToScriptString](): string; + // [Copy](): ObjectField; } // @ts-ignore diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index b25b48339..488f7d6cb 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -115,22 +115,20 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { height={Number(MAX_ROW_HEIGHT)} GetValue={() => { let field = props.Document[props.fieldKey]; - if (field) { - //TODO Types - // return field.ToScriptString(); - return String(field); + if (Field.IsField(field)) { + return Field.toScriptString(field); } return ""; }} SetValue={(value: string) => { - let script = CompileScript(value, { addReturn: true, params: { this: Document.name } }); + let script = CompileScript(value, { addReturn: true, params: { this: Doc.name } }); if (!script.compiled) { return false; } return applyToDoc(props.Document, script.run); }} OnFillDown={async (value: string) => { - let script = CompileScript(value, { addReturn: true, params: { this: Document.name } }); + let script = CompileScript(value, { addReturn: true, params: { this: Doc.name } }); if (!script.compiled) { return; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ba6a4bbab..7a0a02318 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -183,7 +183,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return; } e.stopPropagation(); - const coefficient = 100; + const coefficient = 1000; if (e.ctrlKey) { let deltaScale = (1 - (e.deltaY / coefficient)); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 7a88985c0..2363553df 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -60,10 +60,8 @@ export class KeyValuePair extends React.Component { { let field = FieldValue(props.Document[props.fieldKey]); - if (field) { - //TODO Types - return String(field); - // return field.ToScriptString(); + if (Field.IsField(field)) { + return Field.toScriptString(field); } return ""; }} @@ -75,7 +73,7 @@ export class KeyValuePair extends React.Component { let res = script.run(); if (!res.success) return false; const field = res.result; - if (Field.IsField(field)) { + if (Field.IsField(field, true)) { props.Document[props.fieldKey] = field; return true; } diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index 4314e2132..b22300d0b 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -20,7 +20,7 @@ function applyToDoc(doc: any, key: string | number, scriptString: string): boole } const res = script.run({ this: doc }); if (!res.success) return false; - if (!Field.IsField(res.result)) return false; + if (!Field.IsField(res.result, true)) return false; doc[key] = res.result; return true; } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 08bc2ec4d..b0237d04d 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -19,12 +19,15 @@ export namespace Field { return field[ToScriptString](); } } - export function IsField(field: any): field is Field { + export function IsField(field: any): field is Field; + export function IsField(field: any, includeUndefined: true): field is Field | undefined; + export function IsField(field: any, includeUndefined: boolean = false): field is Field | undefined { return (typeof field === "string") || (typeof field === "number") || (typeof field === "boolean") || (field instanceof ObjectField) - || (field instanceof RefField); + || (field instanceof RefField) + || (includeUndefined && field === undefined); } } export type Field = number | string | boolean | ObjectField | RefField; diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts index a6f8f1cc5..4a2841fb6 100644 --- a/src/new_fields/URLField.ts +++ b/src/new_fields/URLField.ts @@ -18,13 +18,18 @@ export abstract class URLField extends ObjectField { @serializable(url()) readonly url: URL; - constructor(url: URL) { + constructor(url: string); + constructor(url: URL); + constructor(url: URL | string) { super(); + if (typeof url === "string") { + url = new URL(url); + } this.url = url; } [ToScriptString]() { - return `new ${this.constructor.name}(new URL(${this.url.href}))`; + return `new ${this.constructor.name}("${this.url.href}")`; } [Copy](): this { -- cgit v1.2.3-70-g09d2 From 7e5ba95b02e4ead3ee2b41eca1af0acb72d6f7cd Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 21 May 2019 14:15:06 -0400 Subject: fixes for histogram brushing. --- src/client/northstar/dash-fields/HistogramField.ts | 2 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 4 ++- .../CollectionFreeFormLinksView.tsx | 12 +++---- .../collections/collectionFreeForm/MarqueeView.tsx | 38 ++++++++++++---------- src/client/views/nodes/FieldView.tsx | 2 +- 5 files changed, 31 insertions(+), 27 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 31040a474..e6f32272e 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -58,6 +58,6 @@ export class HistogramField extends ObjectField { } [ToScriptString]() { - return "invalid"; + return this.toString(); } } \ No newline at end of file diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index a9646ed31..d7732ee86 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -125,9 +125,11 @@ export class HistogramBox extends React.Component { let mapped = brushingDocs.map((brush, i) => { brush.backgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]; let brushed = DocListCast(brush.brushingDocs); + if (!brushed.length) + return null; return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] }; }); - this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...mapped); + runInAction(() => this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...mapped.filter(m => m) as { l: Doc, b: Doc }[])); } }, { fireImmediately: true }); reaction(() => this.createOperationParamsCache, () => this.HistoOp.Update(), { fireImmediately: true }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index e1ff715d1..c5f7ad0d1 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -32,8 +32,8 @@ export class CollectionFreeFormLinksView extends React.Component)[]) => field.findIndex(brush => { @@ -60,12 +60,12 @@ export class CollectionFreeFormLinksView extends React.Component(); + if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List(); let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []); let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []); - if (dstBrushDocs === undefined) dstTarg.brushingDocs = dstBrushDocs = new List(); - else brushAction(dstBrushDocs); - if (srcBrushDocs === undefined) srcTarg.brushingDocs = srcBrushDocs = new List(); - else brushAction(srcBrushDocs); + brushAction(dstBrushDocs); + brushAction(srcBrushDocs); } }); }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 7ccf480f3..f0ccda140 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -228,6 +228,7 @@ export class MarqueeView extends React.Component if (e.key === "c" || e.key === "s" || e.key === "e" || e.key === "p") { this._commandExecuted = true; e.stopPropagation(); + e.preventDefault(); (e as any).propagationIsStopped = true; let bounds = this.Bounds; let selected = this.marqueeSelect(); @@ -260,25 +261,26 @@ export class MarqueeView extends React.Component if (e.key === "s" || e.key === "p") { - htmlToImage.toPng(this._mainCont.current!, { width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, quality: 0.2 }).then((dataUrl) => { - selected.map(d => { - this.props.removeDocument(d); - d.x = NumCast(d.x) - bounds.left - bounds.width / 2; - d.y = NumCast(d.y) - bounds.top - bounds.height / 2; - d.page = -1; - return d; - }); - let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - summary.proto!.thumbnail = new ImageField(new URL(dataUrl)); - summary.proto!.templates = new List([Templates.ImageOverlay(Math.min(50, bounds.width), bounds.height * Math.min(50, bounds.width) / bounds.width, "thumbnail")]); - newCollection.proto!.summaryDoc = summary; - selected = [newCollection]; - newCollection.x = bounds.left + bounds.width; - //this.props.addDocument(newCollection, false); - summary.proto!.summarizedDocs = new List(selected); - summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight" - this.props.addLiveTextDocument(summary); + // htmlToImage.toPng(this._mainCont.current!, { width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, quality: 0.2 }).then((dataUrl) => { + selected.map(d => { + this.props.removeDocument(d); + d.x = NumCast(d.x) - bounds.left - bounds.width / 2; + d.y = NumCast(d.y) - bounds.top - bounds.height / 2; + d.page = -1; + return d; }); + let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); + // summary.proto!.thumbnail = new ImageField(new URL(dataUrl)); + // summary.proto!.templates = new List([Templates.ImageOverlay(Math.min(50, bounds.width), bounds.height * Math.min(50, bounds.width) / bounds.width, "thumbnail")]); + newCollection.proto!.summaryDoc = summary; + selected = [newCollection]; + newCollection.x = bounds.left + bounds.width; + //this.props.addDocument(newCollection, false); + summary.proto!.summarizedDocs = new List(selected); + summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight" + + this.props.addLiveTextDocument(summary); + // }); } else { this.props.addDocument(newCollection, false); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 5c149af99..092ccb9b0 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -117,7 +117,7 @@ export class FieldView extends React.Component { // return // } else if (!(field instanceof Promise)) { - return

{JSON.stringify(field)}

; + return

{field.toString()}

; } else { return

{"Waiting for server..."}

; -- cgit v1.2.3-70-g09d2 From f196645935814b7f2d3faef0da7fd6c5d46f14f0 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 21 May 2019 18:04:16 -0400 Subject: various fixes --- src/client/util/SearchUtil.ts | 3 +- src/client/views/MainOverlayTextBox.tsx | 2 +- .../views/collections/CollectionTreeView.scss | 4 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 3 +- .../authentication/models/current_user_utils.ts | 46 +++++++++++----------- 6 files changed, 32 insertions(+), 28 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index e8eb70837..28ec8ca14 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -20,6 +20,7 @@ export namespace SearchUtil { export async function GetAliasesOfDocument(doc: Doc): Promise { const proto = await Doc.GetT(doc, "proto", Doc, true); const protoId = (proto || doc)[Id]; - return Search(`{!join from=id to=proto_i}id:${protoId}`, true); + return Search(`proto_i:"${protoId}"`, true); + // return Search(`{!join from=id to=proto_i}id:${protoId}`, true); } } \ No newline at end of file diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 91f626737..9be408049 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -90,7 +90,7 @@ export class MainOverlayTextBox extends React.Component style={{ width: `${textRect.width * s}px`, height: `${textRect.height * s}px` }}> + ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={emptyFunction} />
; } diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 5f82137c6..2f0329fc4 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -46,7 +46,9 @@ .docContainer:hover { .treeViewItem-openRight { - display: inline; + display: inline-block; + // display: inline; + transform: translate(0px, -3px); //TODO Fix this } } diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 092ccb9b0..d3d765eed 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -35,7 +35,7 @@ export interface FieldViewProps { isTopMost: boolean; selectOnLoad: boolean; addDocument?: (document: Doc, allowDuplicates?: boolean) => boolean; - addDocTab: (document: Doc, where: string) => boolean; + addDocTab: (document: Doc, where: string) => void; removeDocument?: (document: Doc) => boolean; moveDocument?: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; ScreenToLocalTransform: () => Transform; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 2363553df..228d07018 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,7 +1,7 @@ import { action, observable } from 'mobx'; import { observer } from "mobx-react"; import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app -import { emptyFunction, returnFalse, returnZero } from '../../../Utils'; +import { emptyFunction, returnFalse, returnZero, returnTrue } from '../../../Utils'; import { CompileScript } from "../../util/Scripting"; import { Transform } from '../../util/Transform'; import { EditableView } from "../EditableView"; @@ -38,6 +38,7 @@ export class KeyValuePair extends React.Component { focus: emptyFunction, PanelWidth: returnZero, PanelHeight: returnZero, + addDocTab: emptyFunction }; let contents = ; let fieldKey = Object.keys(props.Document).indexOf(props.fieldKey) !== -1 ? props.fieldKey : "(" + props.fieldKey + ")"; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index aef2d3f4a..b947f5e01 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -83,29 +83,29 @@ export class CurrentUserUtils { @action static SetNorthstarCatalog(ctlog: Catalog, extras: Catalog[]) { CurrentUserUtils.NorthstarDBCatalog = ctlog; - if (ctlog && ctlog.schemas) { - extras.map(ex => ctlog.schemas!.push(ex)); - return ctlog.schemas.map(async schema => { - let schemaDocuments: Doc[] = []; - let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); - await Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { - promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { - if (field instanceof Doc) { - schemaDocuments.push(field); - } else { - var atmod = new ColumnAttributeModel(attr); - let histoOp = new HistogramOperation(schema.displayName!, - new AttributeTransformationModel(atmod, AggregateFunction.None), - new AttributeTransformationModel(atmod, AggregateFunction.Count), - new AttributeTransformationModel(atmod, AggregateFunction.Count)); - schemaDocuments.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); - } - }))); - return promises; - }, [] as Promise[])); - return CurrentUserUtils._northstarSchemas.push(Docs.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! })); - }); - } + // if (ctlog && ctlog.schemas) { + // extras.map(ex => ctlog.schemas!.push(ex)); + // return ctlog.schemas.map(async schema => { + // let schemaDocuments: Doc[] = []; + // let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); + // await Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { + // promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { + // if (field instanceof Doc) { + // schemaDocuments.push(field); + // } else { + // var atmod = new ColumnAttributeModel(attr); + // let histoOp = new HistogramOperation(schema.displayName!, + // new AttributeTransformationModel(atmod, AggregateFunction.None), + // new AttributeTransformationModel(atmod, AggregateFunction.Count), + // new AttributeTransformationModel(atmod, AggregateFunction.Count)); + // schemaDocuments.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); + // } + // }))); + // return promises; + // }, [] as Promise[])); + // return CurrentUserUtils._northstarSchemas.push(Docs.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! })); + // }); + // } } public static set NorthstarDBCatalog(ctlog: Catalog | undefined) { this._northstarCatalog = ctlog; } -- cgit v1.2.3-70-g09d2 From 54e41cfe7f3538e9cc4b1871a6692b38d21c8c46 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 22 May 2019 10:58:19 -0400 Subject: added shift+ctrl dragging of images natively. changed z-index & ordering to allow videos to swho controls & ink. fixed dragging schema docs to copy --- src/client/documents/Documents.ts | 5 +++-- src/client/views/InkingCanvas.scss | 1 - src/client/views/Main.scss | 2 +- .../views/collections/CollectionSchemaView.tsx | 12 +++++------ .../views/collections/CollectionVideoView.scss | 2 +- .../collectionFreeForm/CollectionFreeFormView.scss | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 14 +++++++----- src/client/views/nodes/ImageBox.tsx | 25 ++++++++++++---------- 9 files changed, 36 insertions(+), 28 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b17544229..323534b2b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -60,6 +60,7 @@ export interface DocumentOptions { borderRounding?: number; schemaColumns?: List; dockingConfig?: string; + dbDoc?: Doc; // [key: string]: Opt; } const delegateKeys = ["x", "y", "width", "height", "panX", "panY"]; @@ -241,7 +242,7 @@ export namespace Docs { return CreateInstance(pdfProto, new PdfField(new URL(url)), options); } - export async function DBDocument(url: string, options: DocumentOptions = {}) { + export async function DBDocument(url: string, options: DocumentOptions = {}, columnOptions: DocumentOptions = {}) { let schemaName = options.title ? options.title : "-no schema-"; let ctlog = await Gateway.Instance.GetSchema(url, schemaName); if (ctlog && ctlog.schemas) { @@ -263,7 +264,7 @@ export namespace Docs { new AttributeTransformationModel(atmod, AggregateFunction.None), new AttributeTransformationModel(atmod, AggregateFunction.Count), new AttributeTransformationModel(atmod, AggregateFunction.Count)); - docs.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); + docs.push(Docs.HistogramDocument(histoOp, { ...columnOptions, width: 200, height: 200, title: attr.displayName! })); } })); }); diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss index 8277ff785..8bcaf41dd 100644 --- a/src/client/views/InkingCanvas.scss +++ b/src/client/views/InkingCanvas.scss @@ -4,7 +4,6 @@ opacity:0.99; .jsx-parser { position:absolute; - z-index: -1; width:100%; height:100%; } diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 302c49c10..385298e18 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -40,7 +40,7 @@ p { ::-webkit-scrollbar { -webkit-appearance: none; - height: 5px; + height: 10px; width: 10px; } diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index bfd70ceae..b793447ff 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -76,9 +76,9 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } onHeaderDrag = (columnName: string) => { - let dbDoc = Cast(this.props.Document.DBDoc, Doc); - if (dbDoc instanceof Doc) { - let columnDocs = DocListCast(dbDoc.data); + let schemaDoc = Cast(this.props.Document.schemaDoc, Doc); + if (schemaDoc instanceof Doc) { + let columnDocs = DocListCast(schemaDoc.data); if (columnDocs) { let ddoc = columnDocs.find(doc => doc.title === columnName); if (ddoc) @@ -109,7 +109,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { let reference = React.createRef(); let onItemDown = (e: React.PointerEvent) => (this.props.CollectionView.props.isSelected() ? - SetupDrag(reference, () => props.Document, this.props.moveDocument)(e) : undefined); + SetupDrag(reference, () => props.Document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e) : undefined); let applyToDoc = (doc: Doc, run: (args?: { [name: string]: any }) => any) => { const res = run({ this: doc }); if (!res.success) return false; @@ -251,10 +251,10 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { let dbName = StrCast(this.props.Document.title); let res = await Gateway.Instance.PostSchema(csv, dbName); if (self.props.CollectionView.props.addDocument) { - let schemaDoc = await Docs.DBDocument("https://www.cs.brown.edu/" + dbName, { title: dbName }); + let schemaDoc = await Docs.DBDocument("https://www.cs.brown.edu/" + dbName, { title: dbName }, { dbDoc: self.props.Document }); if (schemaDoc) { //self.props.CollectionView.props.addDocument(schemaDoc, false); - self.props.Document.DBDoc = schemaDoc; + self.props.Document.schemaDoc = schemaDoc; } } } diff --git a/src/client/views/collections/CollectionVideoView.scss b/src/client/views/collections/CollectionVideoView.scss index db8b84832..9d2c23d3e 100644 --- a/src/client/views/collections/CollectionVideoView.scss +++ b/src/client/views/collections/CollectionVideoView.scss @@ -5,7 +5,7 @@ position: inherit; top: 0; left:0; - + z-index: -1; } .collectionVideoView-time{ color : white; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 063c9e2cf..8557a3db4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -63,6 +63,7 @@ border-radius: $border-radius; box-sizing: border-box; position:absolute; + z-index: -1; .marqueeView { overflow: hidden; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 778071126..8be0766eb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -323,7 +323,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); } - private childViews = () => [, ...this.views]; + private childViews = () => [...this.views, ]; render() { const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`; const easing = () => this.props.Document.panTransformType === "Ease"; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index f0ccda140..6cdb117ff 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -99,19 +99,23 @@ export class MarqueeView extends React.Component let docList: Doc[] = []; let groupAttr: string | number = ""; let rowProto = new Doc(); + rowProto.title = rowProto.Id; rowProto.width = 200; + rowProto.isPrototype = true; for (let i = 1; i < ns.length - 1; i++) { let values = ns[i].split("\t"); if (values.length === 1 && columns.length > 1) { groupAttr = values[0]; continue; } - let doc = Doc.MakeDelegate(rowProto); - columns.forEach((col, i) => doc[columns[i]] = (values.length > i ? ((values[i].indexOf(Number(values[i]).toString()) !== -1) ? Number(values[i]) : values[i]) : undefined)); + let docDataProto = Doc.MakeDelegate(rowProto); + docDataProto.isPrototype = true; + columns.forEach((col, i) => docDataProto[columns[i]] = (values.length > i ? ((values[i].indexOf(Number(values[i]).toString()) !== -1) ? Number(values[i]) : values[i]) : undefined)); if (groupAttr) { - doc._group = groupAttr; + docDataProto._group = groupAttr; } - doc.title = i.toString(); + docDataProto.title = i.toString(); + let doc = Doc.MakeDelegate(docDataProto); doc.width = 200; docList.push(doc); } @@ -269,7 +273,7 @@ export class MarqueeView extends React.Component d.page = -1; return d; }); - let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); + let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "#e2ad32" /* yellow */, title: "-summary-" }); // summary.proto!.thumbnail = new ImageField(new URL(dataUrl)); // summary.proto!.templates = new List([Templates.ImageOverlay(Math.min(50, bounds.width), bounds.height * Math.min(50, bounds.width) / bounds.width, "thumbnail")]); newCollection.proto!.summaryDoc = summary; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index d9d964ee9..71bda6fea 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -93,16 +93,19 @@ export class ImageBox extends DocComponent(ImageD } onPointerDown = (e: React.PointerEvent): void => { - if (Date.now() - this._lastTap < 300) { - if (e.buttons === 1) { - this._downX = e.clientX; - this._downY = e.clientY; - document.removeEventListener("pointerup", this.onPointerUp); - document.addEventListener("pointerup", this.onPointerUp); - } - } else { - this._lastTap = Date.now(); - } + if (e.shiftKey && e.ctrlKey) + e.stopPropagation(); + + // if (Date.now() - this._lastTap < 300) { + // if (e.buttons === 1) { + // this._downX = e.clientX; + // this._downY = e.clientY; + // document.removeEventListener("pointerup", this.onPointerUp); + // document.addEventListener("pointerup", this.onPointerUp); + // } + // } else { + // this._lastTap = Date.now(); + // } } @action onPointerUp = (e: PointerEvent): void => { @@ -204,7 +207,7 @@ export class ImageBox extends DocComponent(ImageD let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; return (
Date: Wed, 22 May 2019 11:57:37 -0400 Subject: Pdf proxy rendering --- src/client/views/nodes/PDFBox.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 3bffdd02d..5b8b15ed8 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -249,6 +249,7 @@ export class PDFBox extends DocComponent(PdfDocumen this.props.Document.thumbnailPage = FieldValue(this.Document.curPage, -1); this._renderAsSvg = false; setTimeout(() => { + runInAction(() => this._smallRetryCount = this._mediumRetryCount = this._largeRetryCount = 0); let nwidth = FieldValue(this.Document.nativeWidth, 0); let nheight = FieldValue(this.Document.nativeHeight, 0); htmlToImage.toPng(this._mainDiv.current!, { width: nwidth, height: nheight, quality: 0.8 }) @@ -325,6 +326,7 @@ export class PDFBox extends DocComponent(PdfDocumen return proxy; } return [ + proxy, this._pageInfo.area.filter(() => this._pageInfo.area).map((element: any) => element), this._currAnno.map((element: any) => element), this.pdfContent @@ -372,7 +374,7 @@ export class PDFBox extends DocComponent(PdfDocumen // else if (this._largeRetryCount < 10) this._curSuffix = "_l"; if (field instanceof ImageField) path = this.choosePath(field.url); // } - return ; + return ; } return (null); } -- cgit v1.2.3-70-g09d2 From 30fdae9e869e0f132c76b4fa99b784e75d6c8dae Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 22 May 2019 19:51:49 -0400 Subject: A bunch of fixes/changes --- src/client/documents/Documents.ts | 2 + src/client/util/DocumentManager.ts | 6 ++- src/client/views/InkingCanvas.scss | 42 ++++++++++++-------- src/client/views/SearchBox.tsx | 10 +++-- .../views/collections/CollectionPDFView.scss | 39 ++++++++++-------- src/client/views/collections/CollectionSubView.tsx | 4 ++ .../views/collections/CollectionVideoView.tsx | 46 +++++++++++++++++++++- .../collections/collectionFreeForm/MarqueeView.tsx | 5 ++- .../views/nodes/CollectionFreeFormDocumentView.tsx | 9 ++++- src/client/views/nodes/DocumentView.tsx | 12 +++--- src/client/views/nodes/ImageBox.tsx | 6 ++- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 16 +++++++- src/client/views/nodes/VideoBox.tsx | 8 +++- 14 files changed, 153 insertions(+), 54 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 323534b2b..ae190a989 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -77,7 +77,9 @@ export namespace DocUtils { linkDoc.proto!.linkTags = "Default"; linkDoc.proto!.linkedTo = target; + linkDoc.proto!.linkedToPage = target.curPage; linkDoc.proto!.linkedFrom = source; + linkDoc.proto!.linkedFromPage = source.curPage; let linkedFrom = Cast(protoTarg.linkedFromDocs, listSpec(Doc)); if (!linkedFrom) { diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index f113ff1d7..65c4b9e4b 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -115,11 +115,11 @@ export class DocumentManager { } @undoBatch - public jumpToDocument = async (docDelegate: Doc, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void): Promise => { + public jumpToDocument = async (docDelegate: Doc, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void, linkPage?: number): Promise => { let doc = Doc.GetProto(docDelegate); - const page = NumCast(doc.page, undefined); const contextDoc = await Cast(doc.annotationOn, Doc); if (contextDoc) { + const page = NumCast(doc.page, linkPage || 0); const curPage = NumCast(contextDoc.curPage, page); if (page !== curPage) contextDoc.curPage = page; } @@ -127,11 +127,13 @@ export class DocumentManager { // using forceDockFunc as a flag for splitting linked to doc to the right...can change later if needed if (!forceDockFunc && (docView = DocumentManager.Instance.getDocumentView(doc))) { docView.props.Document.libraryBrush = true; + if (linkPage !== undefined) docView.props.Document.curPage = linkPage; docView.props.focus(docView.props.Document); } else { if (!contextDoc) { const actualDoc = Doc.MakeAlias(docDelegate); actualDoc.libraryBrush = true; + if (linkPage !== undefined) actualDoc.curPage = linkPage; (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); } else { let contextView: DocumentView | null; diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss index 8bcaf41dd..d95398f17 100644 --- a/src/client/views/InkingCanvas.scss +++ b/src/client/views/InkingCanvas.scss @@ -1,40 +1,50 @@ @import "globalCssVariables"; .inkingCanvas { - opacity:0.99; + opacity: 0.99; + .jsx-parser { - position:absolute; - width:100%; - height:100%; + position: absolute; + width: 100%; + height: 100%; + z-index: -1; // allows annotations to appear on videos when screen is full-size & ... } } -.inkingCanvas-paths-ink, .inkingCanvas-paths-markers, .inkingCanvas-noSelect, .inkingCanvas-canSelect { + +.inkingCanvas-paths-ink, +.inkingCanvas-paths-markers, +.inkingCanvas-noSelect, +.inkingCanvas-canSelect { position: absolute; top: 0; - left:0; + left: 0; width: 8192px; height: 8192px; - cursor:"crosshair"; + cursor: "crosshair"; pointer-events: auto; - + } -.inkingCanvas-canSelect, -.inkingCanvas-noSelect { - top:-50000px; - left:-50000px; + +.inkingCanvas-canSelect, +.inkingCanvas-noSelect { + top: -50000px; + left: -50000px; width: 100000px; height: 100000px; } -.inkingCanvas-noSelect { + +.inkingCanvas-noSelect { pointer-events: none; cursor: "arrow"; } -.inkingCanvas-paths-ink, .inkingCanvas-paths-markers { + +.inkingCanvas-paths-ink, +.inkingCanvas-paths-markers { pointer-events: none; z-index: 10000; // overlays ink on top of everything cursor: "arrow"; } + .inkingCanvas-paths-markers { mix-blend-mode: multiply; -} - +} \ No newline at end of file diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 911fc8d9c..fa9462acf 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -21,6 +21,7 @@ import { DocumentManager } from '../util/DocumentManager'; import { SetupDrag } from '../util/DragManager'; import { Docs } from '../documents/Documents'; import { RouteStore } from '../../server/RouteStore'; +import { NumCast } from '../../new_fields/Types'; library.add(faSearch); library.add(faObjectGroup); @@ -143,18 +144,21 @@ export class SearchBox extends React.Component { }); let x = 0; let y = 0; + let maxy = 300; for (const doc of docs) { doc.x = x; doc.y = y; doc.width = 200; - doc.height = 200; + doc.height = 200 * NumCast(doc.nativeHeight) / NumCast(doc.nativeWidth, 1); + maxy = Math.max(doc.height, maxy); x += 250; if (x > 1000) { + maxy = 300; x = 0; - y += 250; + y += maxy + 25; } } - return Docs.FreeformDocument(docs, { width: 400, height: 400, panX: 175, panY: 175, title: `Search Docs: "${this.searchString}"` }); + return Docs.FreeformDocument(docs, { width: 400, height: 400, panX: 175, panY: 175, backgroundColor: "grey", title: `Search Docs: "${this.searchString}"` }); } // Useful queries: diff --git a/src/client/views/collections/CollectionPDFView.scss b/src/client/views/collections/CollectionPDFView.scss index f6fb79582..50201bae8 100644 --- a/src/client/views/collections/CollectionPDFView.scss +++ b/src/client/views/collections/CollectionPDFView.scss @@ -1,49 +1,56 @@ .collectionPdfView-buttonTray { - top : 15px; - left : 20px; - position: relative; + top: 15px; + left: 20px; + position: relative; transform-origin: left top; position: absolute; } + .collectionPdfView-thumb { - width:25px; - height:25px; + width: 25px; + height: 25px; transform-origin: left top; position: absolute; background: darkgray; } + .collectionPdfView-slider { - width:25px; - height:25px; + width: 25px; + height: 25px; transform-origin: left top; position: absolute; background: lightgray; } -.collectionPdfView-cont{ + +.collectionPdfView-cont { width: 100%; height: 100%; - position: absolute; + position: absolute; top: 0; - left:0; + left: 0; + z-index: -1; } + .collectionPdfView-cont-dragging { span { user-select: none; } } + .collectionPdfView-backward { - color : white; + color: white; font-size: 24px; - top :0px; - left : 0px; + top: 0px; + left: 0px; position: absolute; background-color: rgba(50, 50, 50, 0.2); } + .collectionPdfView-forward { - color : white; + color: white; font-size: 24px; - top :0px; - left : 45px; + top: 0px; + left: 45px; position: absolute; background-color: rgba(50, 50, 50, 0.2); } \ No newline at end of file diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 7800b35df..4a21e4465 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -153,6 +153,10 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { @undoBatch @action protected onDrop(e: React.DragEvent, options: DocumentOptions): void { + if (e.ctrlKey) { + e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl + return; + } let html = e.dataTransfer.getData("text/html"); let text = e.dataTransfer.getData("text/plain"); diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 27f23a1a8..7853544d5 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -1,4 +1,5 @@ import { action, observable, trace } from "mobx"; +import * as htmlToImage from "html-to-image"; import { observer } from "mobx-react"; import { ContextMenu } from "../ContextMenu"; import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; @@ -6,10 +7,14 @@ import React = require("react"); import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; -import { emptyFunction } from "../../../Utils"; +import { emptyFunction, Utils } from "../../../Utils"; import { Id } from "../../../new_fields/FieldSymbols"; import { VideoBox } from "../nodes/VideoBox"; -import { NumCast } from "../../../new_fields/Types"; +import { NumCast, Cast, StrCast } from "../../../new_fields/Types"; +import { VideoField } from "../../../new_fields/URLField"; +import { SearchBox } from "../SearchBox"; +import { DocServer } from "../../DocServer"; +import { Docs, DocUtils } from "../../documents/Documents"; @observer @@ -67,6 +72,43 @@ export class CollectionVideoView extends React.Component { onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 } + + let field = Cast(this.props.Document[this.props.fieldKey], VideoField); + if (field) { + let url = field.url.href; + ContextMenu.Instance.addItem({ + description: "Copy path", event: () => { Utils.CopyText(url); }, icon: "expand-arrows-alt" + }); + } + let width = NumCast(this.props.Document.width); + let height = NumCast(this.props.Document.height); + ContextMenu.Instance.addItem({ + description: "Take Snapshot", event: async () => { + var canvas = document.createElement('canvas'); + canvas.width = 640; + canvas.height = 640 * NumCast(this.props.Document.nativeHeight) / NumCast(this.props.Document.nativeWidth); + var ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions + ctx && ctx.drawImage(this._videoBox!.player!, 0, 0, canvas.width, canvas.height); + + //convert to desired file format + var dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' + // if you want to preview the captured image, + + let filename = encodeURIComponent("snapshot" + this.props.Document.title + "_" + this.props.Document.curPage).replace(/\./g, ""); + SearchBox.convertDataUri(dataUrl, filename).then((returnedFilename) => { + if (returnedFilename) { + let url = DocServer.prepend(returnedFilename); + let imageSummary = Docs.ImageDocument(url, { + x: NumCast(this.props.Document.x) + width, y: NumCast(this.props.Document.y), + width: 150, height: height / width * 150, title: "--snapshot" + NumCast(this.props.Document.curPage) + " image-" + }); + this.props.addDocument && this.props.addDocument(imageSummary, false); + DocUtils.MakeLink(imageSummary, this.props.Document); + } + }); + }, + icon: "expand-arrows-alt" + }); } setVideoBox = (videoBox: VideoBox) => { this._videoBox = videoBox; }; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index d72046800..973ebfbdd 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -296,7 +296,10 @@ export class MarqueeView extends React.Component SearchBox.convertDataUri(dataUrl, "icon" + summary[Id] + "_image").then((returnedFilename) => { if (returnedFilename) { let url = DocServer.prepend(returnedFilename); - let imageSummary = Docs.ImageDocument(url, { x: bounds.left, y: bounds.top + 100 / zoomBasis, width: 150, title: "-summary image-" }); + let imageSummary = Docs.ImageDocument(url, { + x: bounds.left, y: bounds.top + 100 / zoomBasis, + width: 150, height: bounds.height / bounds.width * 150, title: "-summary image-" + }); summary.imageSummary = imageSummary; this.props.addDocument(imageSummary, false); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index aaaa6a9c5..66d91f9c2 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -195,6 +195,7 @@ export class CollectionFreeFormDocumentView extends DocComponent l instanceof Promise)) { let maxLocation = StrCast(linkedFwdDocs[altKey ? 1 : 0].maximizeLocation, "inTab"); - DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], altKey, document => this.props.addDocTab(document, maxLocation)); + DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, document => this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey ? 1 : 0]); } } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 87c88f57c..01c4d82fb 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -234,12 +234,14 @@ export class DocumentView extends DocComponent(Docu makeButton = (e: React.MouseEvent): void => { let doc = this.props.Document.proto ? this.props.Document.proto : this.props.Document; doc.isButton = !BoolCast(doc.isButton, false); - if (doc.isButton && !doc.nativeWidth) { - doc.nativeWidth = this.props.Document[WidthSym](); - doc.nativeHeight = this.props.Document[HeightSym](); - } else { + if (StrCast(doc.layout).indexOf("Formatted") !== -1) { // only need to freeze the dimensions of text boxes since they don't have a native width and height naturally + if (doc.isButton && !doc.nativeWidth) { + doc.nativeWidth = this.props.Document[WidthSym](); + doc.nativeHeight = this.props.Document[HeightSym](); + } else { - doc.nativeWidth = doc.nativeHeight = undefined; + doc.nativeWidth = doc.nativeHeight = undefined; + } } } fullScreenClicked = (e: React.MouseEvent): void => { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 71bda6fea..cc0dc8220 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -47,7 +47,7 @@ export class ImageBox extends DocComponent(ImageD onLoad = (target: any) => { var h = this._imgRef.current!.naturalHeight; var w = this._imgRef.current!.naturalWidth; - if (this._photoIndex === 0 && (this.props as any).id !== "isExpander" && (!this.Document.nativeHeight || !this.Document.nativeWidth)) { + if (this._photoIndex === 0 && (this.props as any).id !== "isExpander" && (!this.Document.nativeWidth || !this.Document.nativeHeight || Math.abs(this.Document.nativeWidth / this.Document.nativeHeight - w / h) > 0.05)) { Doc.SetOnPrototype(this.Document, "nativeHeight", FieldValue(this.Document.nativeWidth, 0) * h / w); this.Document.height = FieldValue(this.Document.width, 0) * h / w; } @@ -165,8 +165,10 @@ export class ImageBox extends DocComponent(ImageD } choosePath(url: URL) { - if (url.protocol === "data" || url.href.indexOf(window.location.origin) === -1) + const lower = url.href.toLowerCase(); + if (url.protocol === "data" || url.href.indexOf(window.location.origin) === -1 || !(lower.endsWith(".png") || lower.endsWith(".jpg") || lower.endsWith(".jpeg"))) { return url.href; + } let ext = path.extname(url.href); return url.href.replace(ext, this._curSuffix + ext); } diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 8cb576786..849f17aa4 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -78,7 +78,7 @@ export class KeyValueBox extends React.Component { let rows: JSX.Element[] = []; let i = 0; - for (let key in ids) { + for (let key of Object.keys(ids).sort()) { rows.push(); } return rows; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 5b8b15ed8..733bc920f 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -23,6 +23,7 @@ import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; var path = require('path'); import React = require("react"); +import { ContextMenu } from "../ContextMenu"; /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx * This method renders PDF and puts all kinds of functionalities such as annotation, highlighting, @@ -357,7 +358,7 @@ export class PDFBox extends DocComponent(PdfDocumen @computed get imageProxyRenderer() { let thumbField = this.props.Document.thumbnail; - if (thumbField && this._renderAsSvg) { + if (thumbField && this._renderAsSvg && NumCast(this.props.Document.thumbnailPage, 0) === this.Document.curPage) { // let transform = this.props.ScreenToLocalTransform().inverse(); let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50; @@ -380,10 +381,21 @@ export class PDFBox extends DocComponent(PdfDocumen } @action onKeyDown = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = true); @action onKeyUp = (e: React.KeyboardEvent) => e.key === "Alt" && (this._alt = false); + onContextMenu = (e: React.MouseEvent): void => { + let field = Cast(this.Document[this.props.fieldKey], PdfField); + if (field) { + let url = field.url.href; + ContextMenu.Instance.addItem({ + description: "Copy path", event: () => { + Utils.CopyText(url); + }, icon: "expand-arrows-alt" + }); + } + } render() { let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); return ( -
+
{this.pdfRenderer}
); diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 6ae55d151..ab57b4b04 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -88,10 +88,14 @@ export class VideoBox extends DocComponent(VideoD if (vref) { vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen); if (this._reactionDisposer) this._reactionDisposer(); - this._reactionDisposer = reaction(() => this.props.Document.curPage, () => - vref.currentTime = NumCast(this.props.Document.curPage, 0), { fireImmediately: true }); + this._reactionDisposer = reaction(() => this.props.Document.curPage, () => { + if (!this.Playing) { + vref.currentTime = NumCast(this.props.Document.curPage, 0); + } + }, { fireImmediately: true }); } } + videoContent(path: string) { let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : ""); return
); diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 3760e378a..449408a61 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -17,6 +17,10 @@ z-index: 25; pointer-events: all; } +.pdfBox-thumbnail { + position: absolute; + width: 100%; +} .pdfButton { pointer-events: all; width: 100px; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 733bc920f..aa29a7170 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -375,7 +375,7 @@ export class PDFBox extends DocComponent(PdfDocumen // else if (this._largeRetryCount < 10) this._curSuffix = "_l"; if (field instanceof ImageField) path = this.choosePath(field.url); // } - return ; + return ; } return (null); } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index ab57b4b04..35ecf12f6 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -10,10 +10,10 @@ import { makeInterface } from "../../../new_fields/Schema"; import { pageSchema } from "./ImageBox"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { VideoField } from "../../../new_fields/URLField"; -import Measure from "react-measure"; import "./VideoBox.scss"; import { RouteStore } from "../../../server/RouteStore"; import { DocServer } from "../../DocServer"; +import { actionFieldDecorator } from "mobx/lib/internal"; type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; const VideoDocument = makeInterface(positionSchema, pageSchema); @@ -22,30 +22,23 @@ const VideoDocument = makeInterface(positionSchema, pageSchema); export class VideoBox extends DocComponent(VideoDocument) { private _reactionDisposer?: IReactionDisposer; private _videoRef: HTMLVideoElement | null = null; - private _loaded: boolean = false; @observable _playTimer?: NodeJS.Timeout = undefined; @observable _fullScreen = false; @observable public Playing: boolean = false; public static LayoutString() { return FieldView.LayoutString(VideoBox); } - public get player(): HTMLVideoElement | undefined { - if (this._videoRef) { - return this._videoRef; - } + public get player(): HTMLVideoElement | null { + return this._videoRef; } - @action - setScaling = (r: any) => { - if (this._loaded) { - // bcz: the nativeHeight should really be set when the document is imported. - var nativeWidth = FieldValue(this.Document.nativeWidth, 0); - var nativeHeight = FieldValue(this.Document.nativeHeight, 0); - var newNativeHeight = nativeWidth * r.offset.height / r.offset.width; - if (!nativeHeight && newNativeHeight !== nativeHeight && !isNaN(newNativeHeight)) { - this.Document.height = newNativeHeight / nativeWidth * FieldValue(this.Document.width, 0); - this.Document.nativeHeight = newNativeHeight; - } - } else { - this._loaded = true; + + videoLoad = () => { + let aspect = this.player!.videoWidth / this.player!.videoHeight; + var nativeWidth = FieldValue(this.Document.nativeWidth, 0); + var nativeHeight = FieldValue(this.Document.nativeHeight, 0); + if (!nativeWidth || !nativeHeight) { + if (!this.Document.nativeWidth) this.Document.nativeWidth = this.player!.videoWidth; + this.Document.nativeHeight = this.Document.nativeWidth / aspect; + this.Document.height = FieldValue(this.Document.width, 0) / aspect; } } @@ -88,22 +81,12 @@ export class VideoBox extends DocComponent(VideoD if (vref) { vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen); if (this._reactionDisposer) this._reactionDisposer(); - this._reactionDisposer = reaction(() => this.props.Document.curPage, () => { - if (!this.Playing) { - vref.currentTime = NumCast(this.props.Document.curPage, 0); - } - }, { fireImmediately: true }); + this._reactionDisposer = reaction(() => this.props.Document.curPage, () => + !this.Playing && (vref.currentTime = this.Document.curPage || 0) + , { fireImmediately: true }); } } - videoContent(path: string) { - let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : ""); - return ; - } - getMp4ForVideo(videoId: string = "JN5beCVArMs") { return new Promise(async (resolve, reject) => { const videoInfoRequestConfig = { @@ -111,7 +94,6 @@ export class VideoBox extends DocComponent(VideoD connection: 'keep-alive', "user-agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/46.0', }, - }; try { let responseSchema: any = {}; @@ -145,9 +127,6 @@ export class VideoBox extends DocComponent(VideoD render() { let field = Cast(this.Document[this.props.fieldKey], VideoField); - if (!field) { - return
Loading
; - } // this.getMp4ForVideo().then((mp4) => { // console.log(mp4); @@ -155,15 +134,12 @@ export class VideoBox extends DocComponent(VideoD // console.log("") // }); // // - let content = this.videoContent(field.url.href); - return NumCast(this.props.Document.nativeHeight) ? - content : - - {({ measureRef }) => -
- {content} -
- } -
; + + let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : ""); + return !field ?
Loading
: + ; } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From e4a298e8e5410af8654e0e2aafd6e21c212ecee1 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 28 May 2019 14:36:02 -0400 Subject: added pasting of img url's with ctrl-b, switched stacking view to a masonry view like pinterest. fixed template overlays. --- package.json | 1 + src/client/documents/Documents.ts | 3 +- src/client/views/Templates.tsx | 10 ++- .../views/collections/CollectionStackingView.scss | 7 ++ .../views/collections/CollectionStackingView.tsx | 62 ++++++++++++--- .../collectionFreeForm/CollectionFreeFormView.scss | 7 ++ .../collections/collectionFreeForm/MarqueeView.tsx | 88 ++++++++++++---------- src/client/views/nodes/ImageBox.tsx | 2 +- 8 files changed, 122 insertions(+), 58 deletions(-) (limited to 'src/client/views/nodes') diff --git a/package.json b/package.json index d5abc808e..df0767b50 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "html-to-image": "^0.1.0", "i": "^0.3.6", "image-data-uri": "^2.0.0", + "imagesloaded": "^4.1.4", "jsonwebtoken": "^8.5.0", "jsx-to-string": "^1.4.0", "lodash": "^4.17.11", diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1f4b76384..4bc0df31f 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -34,6 +34,7 @@ import { StrokeData, InkField } from "../../new_fields/InkField"; import { dropActionType } from "../util/DragManager"; import { DateField } from "../../new_fields/DateField"; import { UndoManager } from "../util/UndoManager"; +import { RouteStore } from "../../server/RouteStore"; var requestImageSize = require('request-image-size'); export interface DocumentOptions { @@ -218,7 +219,7 @@ export namespace Docs { export function ImageDocument(url: string, options: DocumentOptions = {}) { let inst = CreateInstance(imageProto, new ImageField(new URL(url)), options); - requestImageSize(url) + requestImageSize(window.origin + RouteStore.corsProxy + "/" + url) .then((size: any) => { if (!inst.proto!.nativeWidth) { inst.proto!.nativeWidth = size.width; diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 5a99b3d90..303f3f3b8 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -56,10 +56,12 @@ export namespace Templates {
` ); export const Title = new Template("Title", TemplatePosition.InnerTop, - `
{layout}
-
- {props.Document.title} -
` ); + `
+
{layout}
+
+ {props.Document.title} +
+
` ); export const Bullet = new Template("Bullet", TemplatePosition.InnerTop, `
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 803e680e5..6043a813d 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -31,6 +31,13 @@ align-items: center; } + .collectionStackingview-masonryGrid { + display:grid; + width:100%; + height:100%; + position: absolute; + } + .collectionStackingView-description { font-size: 100%; margin-bottom: 1vw; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a1cb73123..a29648d5b 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,36 +1,76 @@ import React = require("react"); import { observer } from "mobx-react"; -import { CollectionSubView } from "./CollectionSubView"; -import Measure from "react-measure"; -import { Doc, WidthSym, HeightSym } from "../../../new_fields/Doc"; +import { CollectionSubView, CollectionViewProps, SubCollectionViewProps } from "./CollectionSubView"; +import { Doc, WidthSym, HeightSym, DocListCast } from "../../../new_fields/Doc"; import { DocumentView } from "../nodes/DocumentView"; import { Transform } from "../../util/Transform"; import { emptyFunction, returnOne } from "../../../Utils"; import "./CollectionStackingView.scss"; -import { runInAction, action, observable, computed } from "mobx"; -import { StrCast } from "../../../new_fields/Types"; +import { action, reaction } from "mobx"; +import { StrCast, NumCast } from "../../../new_fields/Types"; +import { Id } from "../../../new_fields/FieldSymbols"; + + @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform(); + constructor(props: SubCollectionViewProps) { + super(props); + // reaction(() => [this.props.PanelHeight() + this.props.PanelWidth(), + // (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document[this.props.ContainingCollectionView.props.fieldKey])], () => { + // if (this.props.ContainingCollectionView) { + // let allItems = DocListCast(this.props.ContainingCollectionView.props.Document[this.props.ContainingCollectionView.props.fieldKey]); + // for (let x = 0; x < allItems.length; x++) { + // resizeGridItem(allItems[x]); + // } + // } + // } + // ); + } + @action moveDocument = (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean): boolean => { this.props.removeDocument(doc); addDocument(doc); return true; } - render() { const docs = this.childDocs; + let gridGap = 10; + let gridSize = 20; + let itemWidth = NumCast(this.props.Document.itemWidth, 250); + let leftMargin = 20; + let topMargin = 20; + let itemCols = Math.ceil(itemWidth / (gridSize + gridGap)); + let cells = Math.floor((this.props.PanelWidth() - leftMargin) / (itemCols * (gridSize + gridGap))); return ( -
e.stopPropagation()}> -
{StrCast(this.props.Document.documentText, StrCast(this.props.Document.title, "stacking collection"))}
-
+
e.stopPropagation()}> +
{docs.map(d => { - return (
+ let colSpan = Math.ceil((itemWidth + gridGap) / (gridSize + gridGap)); + let rowSpan = Math.ceil((itemWidth / d[WidthSym]() * d[HeightSym]() + gridGap) / (gridSize + gridGap)); + return (
.jsx-parser { + z-index:0; + } //nested freeform views // .collectionfreeformview-container { @@ -52,6 +55,10 @@ position: inherit; height: 100%; } + + >.jsx-parser { + z-index:0; + } .formattedTextBox-cont { background: $light-color-secondary; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 973ebfbdd..64d5301c9 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -83,56 +83,62 @@ export class MarqueeView extends React.Component }); })(); } else if (e.key === "b" && e.ctrlKey) { - //heuristically converts pasted text into a table. - // assumes each entry is separated by a tab - // skips all rows until it gets to a row with more than one entry - // assumes that 1st row has header entry for each column - // assumes subsequent rows have entries for each column header OR - // any row that has only one column is a section header-- this header is then added as a column to subsequent rows until the next header - // assumes each cell is a string or a number e.preventDefault(); - (async () => { - let text: string = await navigator.clipboard.readText(); + navigator.clipboard.readText().then(text => { let ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); - while (ns.length > 0 && ns[0].split("\t").length < 2) { - ns.splice(0, 1); - } - if (ns.length > 0) { - let columns = ns[0].split("\t"); - let docList: Doc[] = []; - let groupAttr: string | number = ""; - let rowProto = new Doc(); - rowProto.title = rowProto.Id; - rowProto.width = 200; - rowProto.isPrototype = true; - for (let i = 1; i < ns.length - 1; i++) { - let values = ns[i].split("\t"); - if (values.length === 1 && columns.length > 1) { - groupAttr = values[0]; - continue; - } - let docDataProto = Doc.MakeDelegate(rowProto); - docDataProto.isPrototype = true; - columns.forEach((col, i) => docDataProto[columns[i]] = (values.length > i ? ((values[i].indexOf(Number(values[i]).toString()) !== -1) ? Number(values[i]) : values[i]) : undefined)); - if (groupAttr) { - docDataProto._group = groupAttr; - } - docDataProto.title = i.toString(); - let doc = Doc.MakeDelegate(docDataProto); - doc.width = 200; - docList.push(doc); - } - let newCol = Docs.SchemaDocument([...(groupAttr ? ["_group"] : []), ...columns.filter(c => c)], docList, { x: x, y: y, title: "droppedTable", width: 300, height: 100 }); - - this.props.addDocument(newCol, false); + if (ns.length === 1 && text.startsWith("http")) { + this.props.addDocument(Docs.ImageDocument(text, { width: 300, x: x, y: y }), false);// paste an image from its URL in the paste buffer + } else { + this.pasteTable(ns, x, y); } - })(); + }); } else { let newBox = Docs.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" }); this.props.addLiveTextDocument(newBox); } e.stopPropagation(); } + //heuristically converts pasted text into a table. + // assumes each entry is separated by a tab + // skips all rows until it gets to a row with more than one entry + // assumes that 1st row has header entry for each column + // assumes subsequent rows have entries for each column header OR + // any row that has only one column is a section header-- this header is then added as a column to subsequent rows until the next header + // assumes each cell is a string or a number + pasteTable(ns: string[], x: number, y: number) { + while (ns.length > 0 && ns[0].split("\t").length < 2) { + ns.splice(0, 1); + } + if (ns.length > 0) { + let columns = ns[0].split("\t"); + let docList: Doc[] = []; + let groupAttr: string | number = ""; + let rowProto = new Doc(); + rowProto.title = rowProto.Id; + rowProto.width = 200; + rowProto.isPrototype = true; + for (let i = 1; i < ns.length - 1; i++) { + let values = ns[i].split("\t"); + if (values.length === 1 && columns.length > 1) { + groupAttr = values[0]; + continue; + } + let docDataProto = Doc.MakeDelegate(rowProto); + docDataProto.isPrototype = true; + columns.forEach((col, i) => docDataProto[columns[i]] = (values.length > i ? ((values[i].indexOf(Number(values[i]).toString()) !== -1) ? Number(values[i]) : values[i]) : undefined)); + if (groupAttr) { + docDataProto._group = groupAttr; + } + docDataProto.title = i.toString(); + let doc = Doc.MakeDelegate(docDataProto); + doc.width = 200; + docList.push(doc); + } + let newCol = Docs.SchemaDocument([...(groupAttr ? ["_group"] : []), ...columns.filter(c => c)], docList, { x: x, y: y, title: "droppedTable", width: 300, height: 100 }); + + this.props.addDocument(newCol, false); + } + } @action onPointerDown = (e: React.PointerEvent): void => { this._downX = this._lastX = e.pageX; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 128f3c6f8..d70068295 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -86,8 +86,8 @@ export class ImageBox extends DocComponent(ImageD onPointerDown = (e: React.PointerEvent): void => { if (e.shiftKey && e.ctrlKey) - e.stopPropagation(); + e.stopPropagation(); // if (Date.now() - this._lastTap < 300) { // if (e.buttons === 1) { // this._downX = e.clientX; -- cgit v1.2.3-70-g09d2 From 435f0c8ef035995001dde92f8e7a04fe35a3a41d Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 28 May 2019 20:00:50 -0400 Subject: Added default values for Document Schemas --- src/client/views/nodes/DocumentView.tsx | 13 +++++++------ src/debug/Repl.tsx | 11 ++++++++--- src/new_fields/Schema.ts | 18 +++++++++++++++--- src/new_fields/Types.ts | 12 +++++++++--- 4 files changed, 39 insertions(+), 15 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 01c4d82fb..2fb794925 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -5,7 +5,7 @@ import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; -import { createSchema, makeInterface } from "../../../new_fields/Schema"; +import { createSchema, makeInterface, defaultSpec } from "../../../new_fields/Schema"; import { BoolCast, Cast, FieldValue, StrCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { emptyFunction, Utils } from "../../../Utils"; @@ -60,15 +60,15 @@ const LinkDoc = makeInterface(linkSchema); export interface DocumentViewProps { ContainingCollectionView: Opt; Document: Doc; - addDocument?: (doc: Document, allowDuplicates?: boolean) => boolean; - removeDocument?: (doc: Document) => boolean; - moveDocument?: (doc: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; + addDocument?: (doc: Doc, allowDuplicates?: boolean) => boolean; + removeDocument?: (doc: Doc) => boolean; + moveDocument?: (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; ScreenToLocalTransform: () => Transform; isTopMost: boolean; ContentScaling: () => number; PanelWidth: () => number; PanelHeight: () => number; - focus: (doc: Document) => void; + focus: (doc: Doc) => void; selectOnLoad: boolean; parentActive: () => boolean; whenActiveChanged: (isActive: boolean) => void; @@ -81,7 +81,8 @@ const schema = createSchema({ layout: "string", nativeWidth: "number", nativeHeight: "number", - backgroundColor: "string" + backgroundColor: "string", + test: defaultSpec("number", 5) }); export const positionSchema = createSchema({ diff --git a/src/debug/Repl.tsx b/src/debug/Repl.tsx index 01acb0e76..c2db3bdcb 100644 --- a/src/debug/Repl.tsx +++ b/src/debug/Repl.tsx @@ -3,6 +3,7 @@ import * as ReactDOM from 'react-dom'; import { observer } from 'mobx-react'; import { observable, computed } from 'mobx'; import { CompileScript } from '../client/util/Scripting'; +import { makeInterface } from '../new_fields/Schema'; @observer class Repl extends React.Component { @@ -15,12 +16,16 @@ class Repl extends React.Component { } onKeyDown = (e: React.KeyboardEvent) => { - if (e.ctrlKey && e.key === "Enter") { - const script = CompileScript(this.text, { addReturn: true, typecheck: false }); + if (!e.ctrlKey && e.key === "Enter") { + e.preventDefault(); + const script = CompileScript(this.text, { + addReturn: true, typecheck: false, + params: { makeInterface: "any" } + }); if (!script.compiled) { this.executedCommands.push({ command: this.text, result: "Compile Error" }); } else { - const result = script.run(); + const result = script.run({ makeInterface }); if (result.success) { this.executedCommands.push({ command: this.text, result: result.result }); } else { diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts index b821baec9..250f3c975 100644 --- a/src/new_fields/Schema.ts +++ b/src/new_fields/Schema.ts @@ -1,4 +1,4 @@ -import { Interface, ToInterface, Cast, ToConstructor, HasTail, Head, Tail, ListSpec, ToType } from "./Types"; +import { Interface, ToInterface, Cast, ToConstructor, HasTail, Head, Tail, ListSpec, ToType, DefaultFieldConstructor } from "./Types"; import { Doc, Field } from "./Doc"; type AllToInterface = { @@ -10,7 +10,7 @@ export const emptySchema = createSchema({}); export const Document = makeInterface(emptySchema); export type Document = makeInterface<[typeof emptySchema]>; -export type makeInterface = Partial> & Doc & { proto: Doc | undefined }; +export type makeInterface = AllToInterface & Doc & { proto: Doc | undefined }; // export function makeInterface(schemas: T): (doc: U) => All; // export function makeInterface(schema: T): (doc: U) => makeInterface; export function makeInterface(...schemas: T): (doc?: Doc) => makeInterface { @@ -24,7 +24,12 @@ export function makeInterface(...schemas: T): (doc?: Doc) get(target: any, prop, receiver) { const field = receiver.doc[prop]; if (prop in schema) { - return Cast(field, (schema as any)[prop]); + const desc = (schema as any)[prop]; + if (typeof desc === "object" && "defaultVal" in desc && "type" in desc) { + return Cast(field, desc.type, desc.defaultVal); + } else { + return Cast(field, (schema as any)[prop]); + } } return field; }, @@ -79,4 +84,11 @@ export function createSchema(schema: T): T & { proto: ToCon export function listSpec>(type: U): ListSpec> { return { List: type as any };//TODO Types +} + +export function defaultSpec>(type: T, defaultVal: ToType): DefaultFieldConstructor> { + return { + type: type as any, + defaultVal + }; } \ No newline at end of file diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 4b4c58eb8..c04dd5e6d 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -2,12 +2,13 @@ import { Field, Opt, FieldResult, Doc } from "./Doc"; import { List } from "./List"; import { RefField } from "./RefField"; -export type ToType | ListSpec> = +export type ToType | ListSpec | DefaultFieldConstructor> = T extends "string" ? string : T extends "number" ? number : T extends "boolean" ? boolean : T extends ListSpec ? List : // T extends { new(...args: any[]): infer R } ? (R | Promise) : never; + T extends DefaultFieldConstructor ? never : T extends { new(...args: any[]): List } ? never : T extends { new(...args: any[]): infer R } ? R : never; @@ -19,12 +20,17 @@ export type ToConstructor = new (...args: any[]) => T; export type ToInterface = { - [P in Exclude]: FieldResult>; + [P in Exclude]: T[P] extends DefaultFieldConstructor ? Exclude, undefined> : FieldResult>; }; // type ListSpec = { List: ToContructor> | ListSpec> }; export type ListSpec = { List: ToConstructor }; +export type DefaultFieldConstructor = { + type: ToConstructor, + defaultVal: T +}; + // type ListType = { 0: List>>, 1: ToType> }[HasTail extends true ? 0 : 1]; export type Head = T extends [any, ...any[]] ? T[0] : never; @@ -34,7 +40,7 @@ export type HasTail = T extends ([] | [any]) ? false : true; //TODO Allow you to optionally specify default values for schemas, which should then make that field not be partial export interface Interface { - [key: string]: ToConstructor | ListSpec; + [key: string]: ToConstructor | ListSpec | DefaultFieldConstructor; // [key: string]: ToConstructor | ListSpec; } -- cgit v1.2.3-70-g09d2 From 732cc8c3aec072525535d246b1177181bbd3f7da Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 29 May 2019 12:06:44 -0400 Subject: improved stacking view and captions templates. --- src/client/documents/Documents.ts | 6 +- src/client/views/MainOverlayTextBox.tsx | 7 +- src/client/views/Templates.tsx | 4 +- .../views/collections/CollectionStackingView.tsx | 125 ++++++++++++--------- src/client/views/collections/CollectionSubView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 6 +- src/client/views/nodes/DocumentContentsView.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 5 + src/client/views/nodes/FormattedTextBox.tsx | 21 +++- 9 files changed, 107 insertions(+), 70 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4bc0df31f..9bf62196f 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -26,7 +26,7 @@ import { OmitKeys } from "../../Utils"; import { ImageField, VideoField, AudioField, PdfField, WebField } from "../../new_fields/URLField"; import { HtmlField } from "../../new_fields/HtmlField"; import { List } from "../../new_fields/List"; -import { Cast } from "../../new_fields/Types"; +import { Cast, NumCast } from "../../new_fields/Types"; import { IconField } from "../../new_fields/IconField"; import { listSpec } from "../../new_fields/Schema"; import { DocServer } from "../DocServer"; @@ -221,10 +221,12 @@ export namespace Docs { let inst = CreateInstance(imageProto, new ImageField(new URL(url)), options); requestImageSize(window.origin + RouteStore.corsProxy + "/" + url) .then((size: any) => { + let aspect = size.height / size.width; if (!inst.proto!.nativeWidth) { inst.proto!.nativeWidth = size.width; } - inst.proto!.nativeHeight = Number(inst.proto!.nativeWidth!) * size.height / size.width; + inst.proto!.nativeHeight = Number(inst.proto!.nativeWidth!) * aspect; + inst.proto!.height = NumCast(inst.proto!.width) * aspect; }) .catch((err: any) => console.log(err)); return inst; diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 9be408049..6e8e6f8ce 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -17,6 +17,7 @@ export class MainOverlayTextBox extends React.Component @observable _textXf: () => Transform = () => Transform.Identity(); private _textFieldKey: string = "data"; private _textColor: string | null = null; + private _textHideOnLeave?: boolean; private _textTargetDiv: HTMLDivElement | undefined; private _textProxyDiv: React.RefObject; @@ -39,9 +40,9 @@ export class MainOverlayTextBox extends React.Component this._textFieldKey = textFieldKey!; this._textXf = tx ? tx : () => Transform.Identity(); this._textTargetDiv = div; + this._textHideOnLeave = FormattedTextBox.InputBoxOverlay && FormattedTextBox.InputBoxOverlay.props.hideOnLeave; if (div) { - if (div.parentElement && div.parentElement instanceof HTMLDivElement && div.parentElement.id === "screenSpace") this._textXf = () => Transform.Identity(); - this._textColor = div.style.color; + this._textColor = (getComputedStyle(div) as any).color; div.style.color = "transparent"; } } @@ -88,7 +89,7 @@ export class MainOverlayTextBox extends React.Component return
-
diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 303f3f3b8..0cd367bcb 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -42,8 +42,8 @@ export namespace Templates { export const Caption = new Template("Caption", TemplatePosition.OutterBottom, `
{layout}
-
- +
+
` ); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a29648d5b..425eecebb 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -4,9 +4,9 @@ import { CollectionSubView, CollectionViewProps, SubCollectionViewProps } from " import { Doc, WidthSym, HeightSym, DocListCast } from "../../../new_fields/Doc"; import { DocumentView } from "../nodes/DocumentView"; import { Transform } from "../../util/Transform"; -import { emptyFunction, returnOne } from "../../../Utils"; +import { emptyFunction, returnOne, Utils } from "../../../Utils"; import "./CollectionStackingView.scss"; -import { action, reaction } from "mobx"; +import { action, reaction, trace, computed } from "mobx"; import { StrCast, NumCast } from "../../../new_fields/Types"; import { Id } from "../../../new_fields/FieldSymbols"; @@ -14,20 +14,13 @@ import { Id } from "../../../new_fields/FieldSymbols"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { - getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform(); + + get gridGap() { return 10; } + get gridSize() { return 20; } + get itemWidth() { return NumCast(this.props.Document.itemWidth, 250); } constructor(props: SubCollectionViewProps) { super(props); - // reaction(() => [this.props.PanelHeight() + this.props.PanelWidth(), - // (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document[this.props.ContainingCollectionView.props.fieldKey])], () => { - // if (this.props.ContainingCollectionView) { - // let allItems = DocListCast(this.props.ContainingCollectionView.props.Document[this.props.ContainingCollectionView.props.fieldKey]); - // for (let x = 0; x < allItems.length; x++) { - // resizeGridItem(allItems[x]); - // } - // } - // } - // ); } @action @@ -36,57 +29,79 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { addDocument(doc); return true; } + getDocTransform(doc: Doc, dref: HTMLDivElement) { + let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); + let outerXf = Utils.GetScreenTransform(this.masonryGridRef!); + let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); + return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.itemWidth); + } + masonryGridRef: HTMLDivElement | null = null; + createRef = (ele: HTMLDivElement | null) => { + this.masonryGridRef = ele; + this.createDropTarget(ele!); + } + @computed + get children() { + return this.childDocs.map(d => { + let colSpan = Math.ceil((this.itemWidth + this.gridGap) / (this.gridSize + this.gridGap)); + let rowSpan = Math.ceil((this.itemWidth / d[WidthSym]() * d[HeightSym]() + this.gridGap) / (this.gridSize + this.gridGap)); + let dref = React.createRef(); + let dxf = () => this.getDocTransform(d, dref.current!); + return (
+ +
); + }) + } + onClick = (e: React.MouseEvent) => { + if (this.props.active()) { + let rect = (this.masonryGridRef!.firstChild! as HTMLElement).getBoundingClientRect(); + if (e.clientX < rect.left || e.clientX > rect.right || e.clientY > rect.bottom) this.props.select(false); + e.stopPropagation(); + } + } render() { - const docs = this.childDocs; - let gridGap = 10; - let gridSize = 20; - let itemWidth = NumCast(this.props.Document.itemWidth, 250); let leftMargin = 20; let topMargin = 20; - let itemCols = Math.ceil(itemWidth / (gridSize + gridGap)); - let cells = Math.floor((this.props.PanelWidth() - leftMargin) / (itemCols * (gridSize + gridGap))); + let itemCols = Math.ceil(this.itemWidth / (this.gridSize + this.gridGap)); + let cells = Math.floor((this.props.PanelWidth() - leftMargin) / (itemCols * (this.gridSize + this.gridGap))); return ( -
e.stopPropagation()}> +
e.stopPropagation()}>
- {docs.map(d => { - let colSpan = Math.ceil((itemWidth + gridGap) / (gridSize + gridGap)); - let rowSpan = Math.ceil((itemWidth / d[WidthSym]() * d[HeightSym]() + gridGap) / (gridSize + gridGap)); - return (
- -
); - })} + {this.children}
); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index c4e72b23a..fe9e12640 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -212,7 +212,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { }).then(async (res: Response) => { (await res.json()).map(action((file: any) => { let path = window.location.origin + file; - let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 600, width: 300, title: dropFileName }); + let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300, title: dropFileName }); docPromise.then(doc => doc && this.props.addDocument(doc)); })); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 66d91f9c2..04e0a91f8 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -256,9 +256,6 @@ export class CollectionFreeFormDocumentView extends DocComponent { this.props.Document.libraryBrush = true; }; - onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; }; - borderRounding = () => { let br = NumCast(this.props.Document.borderRounding); return br >= 0 ? br : @@ -283,8 +280,7 @@ export class CollectionFreeFormDocumentView extends DocComponent boolean, select: (ctrl: boolean) => void, layoutKey: string, + hideOnLeave?: boolean }> { @computed get layout(): string { const layout = Cast(this.props.Document[this.props.layoutKey], "string"); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 01c4d82fb..ed5862660 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -343,6 +343,9 @@ export class DocumentView extends DocComponent(Docu } } + onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; }; + onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; }; + isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed); @@ -366,6 +369,8 @@ export class DocumentView extends DocComponent(Docu transform: `scale(${scaling}, ${scaling})` }} onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick} + + onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave} > {this.contents}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 5afef221c..5b74c2e7e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -50,8 +50,9 @@ library.add(faSmile); // this will edit the document and assign the new value to that field. //] -export interface FormattedTextBoxOverlay { +export interface FormattedTextBoxProps { isOverlay?: boolean; + hideOnLeave?: boolean; } const richTextSchema = createSchema({ @@ -62,7 +63,7 @@ type RichTextDocument = makeInterface<[typeof richTextSchema]>; const RichTextDocument = makeInterface(richTextSchema); @observer -export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxOverlay), RichTextDocument>(RichTextDocument) { +export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) { public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(FormattedTextBox, fieldStr); } @@ -357,6 +358,17 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._undoTyping = UndoManager.StartBatch("undoTyping"); } } + + @observable + _entered = false; + @action + onPointerEnter = (e: React.PointerEvent) => { + this._entered = true; + } + @action + onPointerLeave = (e: React.PointerEvent) => { + this._entered = false; + } render() { let style = this.props.isOverlay ? "scroll" : "hidden"; let rounded = NumCast(this.props.Document.borderRounding) < 0 ? "-rounded" : ""; @@ -364,6 +376,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe return (
-- cgit v1.2.3-70-g09d2 From 9dbf61fccc96f7c4d6bd63e25a7208b82df28705 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 29 May 2019 18:21:03 -0400 Subject: stacking view focus fixes. linkview fixes.- --- src/client/documents/Documents.ts | 3 ++- .../views/collections/CollectionStackingView.scss | 2 +- .../views/collections/CollectionStackingView.tsx | 10 ++++++++-- src/client/views/collections/CollectionView.tsx | 13 +++++++++++++ .../collectionFreeForm/CollectionFreeFormLinksView.tsx | 18 +++++++++++------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 9 +-------- src/client/views/nodes/DocumentView.tsx | 6 ++++++ src/client/views/nodes/FormattedTextBox.tsx | 1 - 9 files changed, 43 insertions(+), 21 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 9bf62196f..fffada459 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -36,6 +36,7 @@ import { DateField } from "../../new_fields/DateField"; import { UndoManager } from "../util/UndoManager"; import { RouteStore } from "../../server/RouteStore"; var requestImageSize = require('request-image-size'); +var path = require('path'); export interface DocumentOptions { x?: number; @@ -218,7 +219,7 @@ export namespace Docs { } export function ImageDocument(url: string, options: DocumentOptions = {}) { - let inst = CreateInstance(imageProto, new ImageField(new URL(url)), options); + let inst = CreateInstance(imageProto, new ImageField(new URL(url)), { title: path.basename(url), ...options }); requestImageSize(window.origin + RouteStore.corsProxy + "/" + url) .then((size: any) => { let aspect = size.height / size.width; diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 6043a813d..0e4a8bb7e 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -8,7 +8,7 @@ width: 100%; height: 100%; position: absolute; - overflow-y: scroll; + overflow-y: auto; min-width: 250px; border-width: 0; box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 425eecebb..6d44aa37d 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -47,14 +47,20 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let rowSpan = Math.ceil((this.itemWidth / d[WidthSym]() * d[HeightSym]() + this.gridGap) / (this.gridSize + this.gridGap)); let dref = React.createRef(); let dxf = () => this.getDocTransform(d, dref.current!); + let childFocus = (doc: Doc) => { + doc.libraryBrush = true; + this.props.focus(this.props.Document); // just focus on this collection, not the underlying document because the API doesn't support adding an offset to focus on and we can't pan zoom our contents to be centered. + } return (
doc) { ContainingCollectionView={this.props.CollectionView} isTopMost={false} ScreenToLocalTransform={dxf} - focus={emptyFunction} + focus={childFocus} ContentScaling={returnOne} PanelWidth={d[WidthSym]} PanelHeight={d[HeightSym]} diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 39c8af4ab..a1e7c7c69 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -13,6 +13,8 @@ import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionTreeView } from "./CollectionTreeView"; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionStackingView } from './CollectionStackingView'; +import { NumCast } from '../../../new_fields/Types'; +import { WidthSym, HeightSym } from '../../../new_fields/Doc'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -42,6 +44,16 @@ export class CollectionView extends React.Component { get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } // bcz: ? Why do we need to compare Id's? + freezeNativeDimensions = (e: React.MouseEvent): void => { + if (NumCast(this.props.Document.nativeWidth)) { + this.props.Document.proto!.nativeWidth = undefined; + this.props.Document.proto!.nativeHeight = undefined; + + } else { + this.props.Document.proto!.nativeWidth = this.props.Document[WidthSym](); + this.props.Document.proto!.nativeHeight = this.props.Document[HeightSym](); + } + } onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Freeform), icon: "signature" }); @@ -51,6 +63,7 @@ export class CollectionView extends React.Component { ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "th-list" }); ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree), icon: "tree" }); ContextMenu.Instance.addItem({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "th-list" }); + ContextMenu.Instance.addItem({ description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", event: this.freezeNativeDimensions, icon: "edit" }); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 85556fb90..6207dc8af 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -95,22 +95,26 @@ export class CollectionFreeFormLinksView extends React.Component { let srcViews = this.documentAnchors(connection.a); let targetViews = this.documentAnchors(connection.b); let possiblePairs: { a: Doc, b: Doc, }[] = []; srcViews.map(sv => targetViews.map(tv => possiblePairs.push({ a: sv.props.Document, b: tv.props.Document }))); - possiblePairs.map(possiblePair => - drawnPairs.reduce((found, drawnPair) => { - let match = (possiblePair.a === drawnPair.a && possiblePair.b === drawnPair.b); + possiblePairs.map(possiblePair => { + if (!drawnPairs.reduce((found, drawnPair) => { + let match1 = (Doc.AreProtosEqual(possiblePair.a, drawnPair.a) && Doc.AreProtosEqual(possiblePair.b, drawnPair.b)); + let match2 = (Doc.AreProtosEqual(possiblePair.a, drawnPair.b) && Doc.AreProtosEqual(possiblePair.b, drawnPair.a)); + let match = match1 || match2; if (match && !drawnPair.l.reduce((found, link) => found || link[Id] === connection.l[Id], false)) { drawnPair.l.push(connection.l); } return match || found; - }, false) - || - drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] }) - ); + }, false)) { + console.log("A" + possiblePair.a[Id] + " B" + possiblePair.b[Id] + " L" + connection.l[Id]); + drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] }) + } + }); return drawnPairs; }, [] as { a: Doc, b: Doc, l: Doc[] }[]); return connections.map(c => { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 64d5301c9..14dbe1899 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -87,7 +87,7 @@ export class MarqueeView extends React.Component navigator.clipboard.readText().then(text => { let ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); if (ns.length === 1 && text.startsWith("http")) { - this.props.addDocument(Docs.ImageDocument(text, { width: 300, x: x, y: y }), false);// paste an image from its URL in the paste buffer + this.props.addDocument(Docs.ImageDocument(text, { nativeWidth: 300, width: 300, x: x, y: y }), false);// paste an image from its URL in the paste buffer } else { this.pasteTable(ns, x, y); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 04e0a91f8..5f4d9e9ec 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -280,16 +280,9 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu
{ if (NumCast(this.props.Document.nativeWidth)) { this.props.Document.proto!.nativeWidth = undefined; -- cgit v1.2.3-70-g09d2 From 83edfcd06b659839f161121728de02aca91d4af8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 30 May 2019 00:20:35 -0400 Subject: added image rotation. added double click on stacking views. need to cleanup/fix DocumentView click events --- .../views/collections/CollectionStackingView.scss | 2 +- .../views/collections/CollectionStackingView.tsx | 15 +++++++++++---- .../views/nodes/CollectionFreeFormDocumentView.tsx | 21 +-------------------- src/client/views/nodes/DocumentView.tsx | 12 +++++++++++- src/client/views/nodes/ImageBox.tsx | 19 +++++++++++++++++-- 5 files changed, 41 insertions(+), 28 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 0e4a8bb7e..4d240342c 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -31,7 +31,7 @@ align-items: center; } - .collectionStackingview-masonryGrid { + .collectionStackingView-masonryGrid { display:grid; width:100%; height:100%; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 6d44aa37d..943e8dd5f 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -83,10 +83,17 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }) } onClick = (e: React.MouseEvent) => { + let hitBackground = (e.target as any).className === "collectionStackingView-masonryGrid" || + (e.target as any).className === "collectionStackingView"; if (this.props.active()) { - let rect = (this.masonryGridRef!.firstChild! as HTMLElement).getBoundingClientRect(); - if (e.clientX < rect.left || e.clientX > rect.right || e.clientY > rect.bottom) this.props.select(false); - e.stopPropagation(); + if (!hitBackground) + e.stopPropagation(); + } + if (hitBackground) { + if (!this.props.active() && this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.active()) { + e.stopPropagation(); + } + this.props.select(false); } } render() { @@ -96,7 +103,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let cells = Math.floor((this.props.PanelWidth() - leftMargin) / (itemCols * (this.gridSize + this.gridGap))); return (
e.stopPropagation()}> -
{ - document.removeEventListener("pointerup", this.onPointerUp); - if (Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2) { - this._doubleTap = true; - } - } onClick = async (e: React.MouseEvent) => { e.stopPropagation(); - if (this._doubleTap) { - this.props.addDocTab(this.props.Document, "inTab"); - SelectionManager.DeselectAll(); - this.props.Document.libraryBrush = false; - } let altKey = e.altKey; let ctrlKey = e.ctrlKey; if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 98f4f050a..36c14fbf2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -183,13 +183,21 @@ export class DocumentView extends DocComponent(Docu } } + _doubleTap = false; onClick = (e: React.MouseEvent): void => { - if (CurrentUserUtils.MainDocId !== this.props.Document[Id] && + if (this._doubleTap && !this.props.isTopMost) { + this.props.addDocTab(this.props.Document, "inTab"); + SelectionManager.DeselectAll(); + this.props.Document.libraryBrush = false; + e.stopPropagation(); + } + else if (CurrentUserUtils.MainDocId !== this.props.Document[Id] && (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { SelectionManager.SelectDoc(this, e.ctrlKey); } } + private _lastTap: number = 0; _hitExpander = false; onPointerDown = (e: React.PointerEvent): void => { this._downX = e.clientX; @@ -222,6 +230,8 @@ export class DocumentView extends DocComponent(Docu onPointerUp = (e: PointerEvent): void => { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); + this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2); + this._lastTap = Date.now(); } deleteClicked = (): void => { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index d70068295..8ea6c5436 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -12,11 +12,11 @@ import React = require("react"); import { createSchema, makeInterface, listSpec } from '../../../new_fields/Schema'; import { DocComponent } from '../DocComponent'; import { positionSchema } from './DocumentView'; -import { FieldValue, Cast, StrCast, PromiseValue } from '../../../new_fields/Types'; +import { FieldValue, Cast, StrCast, PromiseValue, NumCast } from '../../../new_fields/Types'; import { ImageField } from '../../../new_fields/URLField'; import { List } from '../../../new_fields/List'; import { InkingControl } from '../InkingControl'; -import { Doc } from '../../../new_fields/Doc'; +import { Doc, WidthSym, HeightSym } from '../../../new_fields/Doc'; import { faImage } from '@fortawesome/free-solid-svg-icons'; import { library } from '@fortawesome/fontawesome-svg-core'; var path = require('path'); @@ -136,6 +136,17 @@ export class ImageBox extends DocComponent(ImageD Utils.CopyText(url); }, icon: "expand-arrows-alt" }); + ContextMenu.Instance.addItem({ + description: "Rotate", event: action(() => { + this.props.Document.rotation = (NumCast(this.props.Document.rotation) + 90) % 360; + let nw = this.props.Document.nativeWidth; + this.props.Document.nativeWidth = this.props.Document.nativeHeight; + this.props.Document.nativeHeight = nw; + let w = this.props.Document.width; + this.props.Document.width = this.props.Document.height; + this.props.Document.height = w; + }), icon: "expand-arrows-alt" + }); } } @@ -199,6 +210,9 @@ export class ImageBox extends DocComponent(ImageD else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => this.choosePath((p as ImageField).url)); // } let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; + let rotation = NumCast(this.props.Document.rotation, 0); + let aspect = (rotation % 180) ? this.props.Document[HeightSym]() / this.props.Document[WidthSym]() : 1; + let shift = (rotation % 180) ? (this.props.Document[HeightSym]() - this.props.Document[WidthSym]() / aspect) / 2 : 0; return (
(ImageD Date: Thu, 30 May 2019 10:51:00 -0400 Subject: cleaned up event handling for documentviews. fixed context menu closing. --- src/client/documents/Documents.ts | 2 +- src/client/views/ContextMenu.tsx | 7 +- src/client/views/ContextMenuItem.tsx | 34 +++-- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/MainView.tsx | 1 - .../views/collections/CollectionBaseView.tsx | 1 + .../views/collections/CollectionDockingView.tsx | 1 - .../views/collections/CollectionSchemaView.tsx | 1 - .../views/collections/CollectionStackingView.tsx | 28 +---- .../views/collections/CollectionTreeView.tsx | 22 ++-- .../CollectionFreeFormLinksView.tsx | 1 - .../collectionFreeForm/CollectionFreeFormView.tsx | 1 - .../views/nodes/CollectionFreeFormDocumentView.tsx | 119 ------------------ src/client/views/nodes/DocumentView.tsx | 140 ++++++++++++++++----- src/client/views/nodes/FieldView.tsx | 1 - 15 files changed, 153 insertions(+), 208 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index fffada459..ab61b915c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -295,7 +295,7 @@ export namespace Docs { return CreateInstance(webProto, new HtmlField(html), options); } export function KVPDocument(document: Doc, options: DocumentOptions = {}) { - return CreateInstance(kvpProto, document, options); + return CreateInstance(kvpProto, document, { title: document.title + ".kvp", ...options }); } export function FreeformDocument(documents: Array, options: DocumentOptions, makePrototype: boolean = true) { if (!makePrototype) { diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 542d259d6..da374455e 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -81,6 +81,11 @@ export class ContextMenu extends React.Component { return false; } + @action + closeMenu = () => { + this.clearItems(); + } + render() { let style = this._yRelativeToTop ? { left: this._pageX, top: this._pageY, display: this._display } : { left: this._pageX, bottom: this._pageY, display: this._display }; @@ -95,7 +100,7 @@ export class ContextMenu extends React.Component { {this._items.filter(prop => prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1). - map(prop => )} + map(prop => )}
); } diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index b9239dac9..63347e076 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -8,11 +8,13 @@ export interface OriginalMenuProps { description: string; event: (e: React.MouseEvent) => void; icon?: IconProp; //maybe should be optional (icon?) + closeMenu?: () => void; } export interface SubmenuProps { description: string; subitems: ContextMenuProps[]; + closeMenu?: () => void; } export interface ContextMenuItemProps { @@ -32,30 +34,36 @@ export class ContextMenuItem extends React.Component { } } + handleEvent = (e: React.MouseEvent) => { + if ("event" in this.props) { + this.props.event(e); + this.props.closeMenu && this.props.closeMenu(); + } + } + render() { if ("event" in this.props) { return ( -
+
{this.props.icon ? : } -
{this.props.description}
+
+ {this.props.description} +
); } else { - let submenu = null; - if (this.overItem) { - submenu = ( -
- {this._items.map(prop => )} -
- ); - } + let submenu = !this.overItem ? (null) : +
+ {this._items.map(prop => )} +
; return ( -
{ this.overItem = true; })} - onMouseLeave={action(() => this.overItem = false)}> -
{this.props.description}
+
{ this.overItem = true; })} onMouseLeave={action(() => this.overItem = false)}> +
+ {this.props.description} +
{submenu}
); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 319e91337..e06fd6119 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -251,7 +251,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } if (!this._removeIcon) { if (selectedDocs.length === 1) { - this.getIconDoc(selectedDocs[0]).then(icon => selectedDocs[0].props.toggleMinimized()); + this.getIconDoc(selectedDocs[0]).then(icon => selectedDocs[0].toggleMinimized()); } else if (Math.abs(e.pageX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.pageY - this._downY) < Utils.DRAG_THRESHOLD) { let docViews = SelectionManager.ViewsSortedVertically(); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 438607157..74dafadc4 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -184,7 +184,6 @@ export class MainView extends React.Component { let mainCont = this.mainContainer; let content = !mainCont ? (null) : { @action.bound removeDocument(doc: Doc): boolean { + SelectionManager.DeselectAll(); const props = this.props; //TODO This won't create the field if it doesn't already exist const value = Cast(props.Document[props.fieldKey], listSpec(Doc), []); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 180a8be46..b6076b5f7 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -466,7 +466,6 @@ export class DockedFrameRenderer extends React.Component {
doc) { - + _masonryGridRef: HTMLDivElement | null = null; get gridGap() { return 10; } get gridSize() { return 20; } get itemWidth() { return NumCast(this.props.Document.itemWidth, 250); } - constructor(props: SubCollectionViewProps) { - super(props); - } - @action moveDocument = (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean): boolean => { this.props.removeDocument(doc); @@ -31,13 +27,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } getDocTransform(doc: Doc, dref: HTMLDivElement) { let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); - let outerXf = Utils.GetScreenTransform(this.masonryGridRef!); + let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.itemWidth); } - masonryGridRef: HTMLDivElement | null = null; createRef = (ele: HTMLDivElement | null) => { - this.masonryGridRef = ele; + this._masonryGridRef = ele; this.createDropTarget(ele!); } @computed @@ -77,32 +72,17 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { parentActive={this.props.active} addDocTab={this.props.addDocTab} bringToFront={emptyFunction} - toggleMinimized={emptyFunction} whenActiveChanged={this.props.whenActiveChanged} />
); }) } - onClick = (e: React.MouseEvent) => { - let hitBackground = (e.target as any).className === "collectionStackingView-masonryGrid" || - (e.target as any).className === "collectionStackingView"; - if (this.props.active()) { - if (!hitBackground) - e.stopPropagation(); - } - if (hitBackground) { - if (!this.props.active() && this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.active()) { - e.stopPropagation(); - } - this.props.select(false); - } - } render() { let leftMargin = 20; let topMargin = 20; let itemCols = Math.ceil(this.itemWidth / (this.gridSize + this.gridGap)); let cells = Math.floor((this.props.PanelWidth() - leftMargin) / (itemCols * (this.gridSize + this.gridGap))); return ( -
e.stopPropagation()}> +
e.stopPropagation()}>
void; moveDocument: DragManager.MoveFunction; dropAction: "alias" | "copy" | undefined; + addDocTab: (doc: Doc, where: string) => void; } export enum BulletType { @@ -140,19 +141,12 @@ class TreeView extends React.Component { onWorkspaceContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.props.document)) }); - ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.document) }); - ContextMenu.Instance.addItem({ - description: "Open Fields", event: () => CollectionDockingView.Instance.AddRightSplit(Docs.KVPDocument(this.props.document, - { title: this.props.document.title + ".kvp", width: 300, height: 300 })) - }); + ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight") }); + ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.KVPDocument(this.props.document, { width: 300, height: 300 }), "onRight") }); if (DocumentManager.Instance.getDocumentViews(this.props.document).length) { ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.props.document).map(view => view.props.focus(this.props.document)) }); } - ContextMenu.Instance.addItem({ - description: "Delete", event: undoBatch(() => { - this.props.deleteDoc(this.props.document); - }) - }); + ContextMenu.Instance.addItem({ description: "Delete", event: undoBatch(() => this.props.deleteDoc(this.props.document)) }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); e.stopPropagation(); } @@ -180,7 +174,7 @@ class TreeView extends React.Component { {(key === "data") ? (null) : {key}}
- {TreeView.GetChildElements(doc instanceof Doc ? [doc] : docList, key !== "data", (doc: Doc) => this.remove(doc, key), this.move, this.props.dropAction)} + {TreeView.GetChildElements(doc instanceof Doc ? [doc] : docList, key !== "data", (doc: Doc) => this.remove(doc, key), this.move, this.props.dropAction, this.props.addDocTab)}
); } else { @@ -197,9 +191,9 @@ class TreeView extends React.Component {
; } - public static GetChildElements(docs: Doc[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { + public static GetChildElements(docs: Doc[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType, addDocTab: (doc: Doc, where: string) => void) { return docs.filter(child => !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).map(child => - ); + ); } } @@ -225,7 +219,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { if (!this.childDocs) { return (null); } - let childElements = TreeView.GetChildElements(this.childDocs, false, this.remove, this.props.moveDocument, dropAction); + let childElements = TreeView.GetChildElements(this.childDocs, false, this.remove, this.props.moveDocument, dropAction, this.props.addDocTab); return (
{ let srcViews = this.documentAnchors(connection.a); let targetViews = this.documentAnchors(connection.b); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d1c4fb72d..1a1614ac7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -279,7 +279,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getDocumentViewProps(document: Doc): DocumentViewProps { return { Document: document, - toggleMinimized: emptyFunction, addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, moveDocument: this.props.moveDocument, diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 5d11e051d..411e8c059 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -30,9 +30,6 @@ const FreeformDocument = makeInterface(schema, positionSchema); @observer export class CollectionFreeFormDocumentView extends DocComponent(FreeformDocument) { private _mainCont = React.createRef(); - private _downX: number = 0; - private _downY: number = 0; - private _doubleTap = false; _bringToFrontDisposer?: IReactionDisposer; @computed get transform() { @@ -62,7 +59,6 @@ export class CollectionFreeFormDocumentView extends DocComponent this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; panelWidth = () => this.props.PanelWidth(); panelHeight = () => this.props.PanelHeight(); - toggleMinimized = async () => this.toggleIcon(await DocListCastAsync(this.props.Document.maximizedDocs)); getTransform = (): Transform => this.props.ScreenToLocalTransform() .translate(-this.X, -this.Y) .scale(1 / this.contentScaling()).scale(1 / this.zoom) @@ -70,7 +66,6 @@ export class CollectionFreeFormDocumentView extends DocComponent => { - SelectionManager.DeselectAll(); - let isMinimized: boolean | undefined; - let minimizedDoc: Doc | undefined = this.props.Document; - if (!maximizedDocs) { - minimizedDoc = await Cast(this.props.Document.minimizedDoc, Doc); - if (minimizedDoc) maximizedDocs = await DocListCastAsync(minimizedDoc.maximizedDocs); - } - if (minimizedDoc && maximizedDocs) { - let minimizedTarget = minimizedDoc; - if (!CollectionFreeFormDocumentView._undoBatch) { - CollectionFreeFormDocumentView._undoBatch = UndoManager.StartBatch("iconAnimating"); - } - maximizedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => { - let iconAnimating = Cast(maximizedDoc.isIconAnimating, List); - if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) { - if (isMinimized === undefined) { - isMinimized = BoolCast(maximizedDoc.isMinimized, false); - } - let minx = NumCast(minimizedTarget.x, undefined) + NumCast(minimizedTarget.width, undefined) / 2; - let miny = NumCast(minimizedTarget.y, undefined) + NumCast(minimizedTarget.height, undefined) / 2; - if (minx !== undefined && miny !== undefined) { - let scrpt = this.props.ScreenToLocalTransform().inverse().transformPoint(minx, miny); - maximizedDoc.willMaximize = isMinimized; - maximizedDoc.isMinimized = false; - maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]); - } - } - }); - setTimeout(() => { - CollectionFreeFormDocumentView._undoBatch && CollectionFreeFormDocumentView._undoBatch.end(); - CollectionFreeFormDocumentView._undoBatch = undefined; - }, 500); - } - } - static _undoBatch?: UndoManager.Batch = undefined; - onPointerDown = (e: React.PointerEvent): void => { - this._downX = e.clientX; - this._downY = e.clientY; - this._doubleTap = false; - if (e.button === 0 && e.altKey) { - e.stopPropagation(); // prevents panning from happening on collection if shift is pressed after a document drag has started - } // allow pointer down to go through otherwise so that marquees can be drawn starting over a document - - if (e.button === 0) { - e.preventDefault(); // prevents Firefox from dragging images (we want to do that ourself) - } - } - onClick = async (e: React.MouseEvent) => { - e.stopPropagation(); - let altKey = e.altKey; - let ctrlKey = e.ctrlKey; - if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && - Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { - let isExpander = (e.target as any).id === "isExpander"; - if (BoolCast(this.props.Document.isButton, false) || isExpander) { - SelectionManager.DeselectAll(); - let subBulletDocs = await DocListCastAsync(this.props.Document.subBulletDocs); - let maximizedDocs = await DocListCastAsync(this.props.Document.maximizedDocs); - let summarizedDocs = await DocListCastAsync(this.props.Document.summarizedDocs); - let linkedToDocs = await DocListCastAsync(this.props.Document.linkedToDocs, []); - let linkedFromDocs = await DocListCastAsync(this.props.Document.linkedFromDocs, []); - let expandedDocs: Doc[] = []; - expandedDocs = subBulletDocs ? [...subBulletDocs, ...expandedDocs] : expandedDocs; - expandedDocs = maximizedDocs ? [...maximizedDocs, ...expandedDocs] : expandedDocs; - expandedDocs = summarizedDocs ? [...summarizedDocs, ...expandedDocs] : expandedDocs; - // let expandedDocs = [...(subBulletDocs ? subBulletDocs : []), ...(maximizedDocs ? maximizedDocs : []), ...(summarizedDocs ? summarizedDocs : []),]; - if (expandedDocs.length) { // bcz: need a better way to associate behaviors with click events on widget-documents - let expandedProtoDocs = expandedDocs.map(doc => Doc.GetProto(doc)); - let maxLocation = StrCast(this.props.Document.maximizeLocation, "inPlace"); - let getDispDoc = (target: Doc) => Object.getOwnPropertyNames(target).indexOf("isPrototype") === -1 ? target : Doc.MakeDelegate(target); - if (altKey) { - maxLocation = this.props.Document.maximizeLocation = (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace"); - if (!maxLocation || maxLocation === "inPlace") { - let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView); - let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized, false), false); - expandedDocs.forEach(maxDoc => Doc.GetProto(maxDoc).isMinimized = false); - let hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView); - if (!hasView) { - this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(getDispDoc(maxDoc), false)); - } - expandedProtoDocs.forEach(maxDoc => maxDoc.isMinimized = wasMinimized); - } - } - if (maxLocation && maxLocation !== "inPlace") { - let dataDocs = DocListCast(CollectionDockingView.Instance.props.Document.data); - if (dataDocs) { - expandedDocs.forEach(maxDoc => - (!CollectionDockingView.Instance.CloseRightSplit(Doc.GetProto(maxDoc)) && - this.props.addDocTab(getDispDoc(maxDoc), maxLocation))); - } - } else { - this.toggleIcon(expandedProtoDocs); - } - } - else if (linkedToDocs.length || linkedFromDocs.length) { - let linkedFwdDocs = [ - linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : expandedDocs[0], - linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : expandedDocs[0]]; - - let linkedFwdPage = [ - linkedToDocs.length ? NumCast(linkedToDocs[0].linkedToPage, undefined) : linkedFromDocs.length ? NumCast(linkedFromDocs[0].linkedFromPage, undefined) : undefined, - linkedFromDocs.length ? NumCast(linkedFromDocs[0].linkedFromPage, undefined) : linkedToDocs.length ? NumCast(linkedToDocs[0].linkedToPage, undefined) : undefined]; - if (!linkedFwdDocs.some(l => l instanceof Promise)) { - let maxLocation = StrCast(linkedFwdDocs[altKey ? 1 : 0].maximizeLocation, "inTab"); - DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, document => this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey ? 1 : 0]); - } - } - } - } - } borderRounding = () => { let br = NumCast(this.props.Document.borderRounding); @@ -261,8 +144,6 @@ export class CollectionFreeFormDocumentView extends DocComponent boolean; whenActiveChanged: (isActive: boolean) => void; - toggleMinimized: () => void; bringToFront: (doc: Doc) => void; addDocTab: (doc: Doc, where: string) => void; + whenClicked?: () => void; } const schema = createSchema({ @@ -103,6 +103,9 @@ const Document = makeInterface(schema); export class DocumentView extends DocComponent(Document) { private _downX: number = 0; private _downY: number = 0; + private _lastTap: number = 0; + private _doubleTap = false; + private _hitExpander = false; private _mainCont = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; @@ -182,23 +185,112 @@ export class DocumentView extends DocComponent(Docu }); } } + toggleMinimized = async () => { + let minimizedDoc = await Cast(this.props.Document.minimizedDoc, Doc); + if (minimizedDoc) { + let scrpt = this.props.ScreenToLocalTransform().inverse().transformPoint( + NumCast(minimizedDoc.x) - NumCast(this.Document.x), NumCast(minimizedDoc.y) - NumCast(this.Document.y)); + this.collapseToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs)); + } + } - _doubleTap = false; - onClick = (e: React.MouseEvent): void => { + static _undoBatch?: UndoManager.Batch = undefined; + @action + public collapseToPoint = async (scrpt: number[], expandedDocs: Doc[] | undefined): Promise => { + SelectionManager.DeselectAll(); + if (expandedDocs) { + if (!DocumentView._undoBatch) { + DocumentView._undoBatch = UndoManager.StartBatch("iconAnimating"); + } + let isMinimized: boolean | undefined; + expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => { + let iconAnimating = Cast(maximizedDoc.isIconAnimating, List); + if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) { + if (isMinimized === undefined) { + isMinimized = BoolCast(maximizedDoc.isMinimized, false); + } + maximizedDoc.willMaximize = isMinimized; + maximizedDoc.isMinimized = false; + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]); + } + }); + setTimeout(() => { + DocumentView._undoBatch && DocumentView._undoBatch.end(); + DocumentView._undoBatch = undefined; + }, 500); + } + } + onClick = async (e: React.MouseEvent) => { + e.stopPropagation(); + let altKey = e.altKey; + let ctrlKey = e.ctrlKey; if (this._doubleTap && !this.props.isTopMost) { this.props.addDocTab(this.props.Document, "inTab"); SelectionManager.DeselectAll(); this.props.Document.libraryBrush = false; - e.stopPropagation(); } else if (CurrentUserUtils.MainDocId !== this.props.Document[Id] && (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { SelectionManager.SelectDoc(this, e.ctrlKey); + let isExpander = (e.target as any).id === "isExpander"; + if (BoolCast(this.props.Document.isButton, false) || isExpander) { + SelectionManager.DeselectAll(); + let subBulletDocs = await DocListCastAsync(this.props.Document.subBulletDocs); + let maximizedDocs = await DocListCastAsync(this.props.Document.maximizedDocs); + let summarizedDocs = await DocListCastAsync(this.props.Document.summarizedDocs); + let linkedToDocs = await DocListCastAsync(this.props.Document.linkedToDocs, []); + let linkedFromDocs = await DocListCastAsync(this.props.Document.linkedFromDocs, []); + let expandedDocs: Doc[] = []; + expandedDocs = subBulletDocs ? [...subBulletDocs, ...expandedDocs] : expandedDocs; + expandedDocs = maximizedDocs ? [...maximizedDocs, ...expandedDocs] : expandedDocs; + expandedDocs = summarizedDocs ? [...summarizedDocs, ...expandedDocs] : expandedDocs; + // let expandedDocs = [...(subBulletDocs ? subBulletDocs : []), ...(maximizedDocs ? maximizedDocs : []), ...(summarizedDocs ? summarizedDocs : []),]; + if (expandedDocs.length) { // bcz: need a better way to associate behaviors with click events on widget-documents + let expandedProtoDocs = expandedDocs.map(doc => Doc.GetProto(doc)); + let maxLocation = StrCast(this.props.Document.maximizeLocation, "inPlace"); + let getDispDoc = (target: Doc) => Object.getOwnPropertyNames(target).indexOf("isPrototype") === -1 ? target : Doc.MakeDelegate(target); + if (altKey) { + maxLocation = this.props.Document.maximizeLocation = (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace"); + if (!maxLocation || maxLocation === "inPlace") { + let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView); + let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized, false), false); + expandedDocs.forEach(maxDoc => Doc.GetProto(maxDoc).isMinimized = false); + let hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView); + if (!hasView) { + this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(getDispDoc(maxDoc), false)); + } + expandedProtoDocs.forEach(maxDoc => maxDoc.isMinimized = wasMinimized); + } + } + if (maxLocation && maxLocation !== "inPlace") { + let dataDocs = DocListCast(CollectionDockingView.Instance.props.Document.data); + if (dataDocs) { + expandedDocs.forEach(maxDoc => + (!CollectionDockingView.Instance.CloseRightSplit(Doc.GetProto(maxDoc)) && + this.props.addDocTab(getDispDoc(maxDoc), maxLocation))); + } + } else { + let scrpt = this.props.ScreenToLocalTransform().inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2); + this.collapseToPoint(scrpt, expandedProtoDocs); + } + } + else if (linkedToDocs.length || linkedFromDocs.length) { + let linkedFwdDocs = [ + linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : expandedDocs[0], + linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : expandedDocs[0]]; + + let linkedFwdPage = [ + linkedToDocs.length ? NumCast(linkedToDocs[0].linkedToPage, undefined) : linkedFromDocs.length ? NumCast(linkedFromDocs[0].linkedFromPage, undefined) : undefined, + linkedFromDocs.length ? NumCast(linkedFromDocs[0].linkedFromPage, undefined) : linkedToDocs.length ? NumCast(linkedToDocs[0].linkedToPage, undefined) : undefined]; + if (!linkedFwdDocs.some(l => l instanceof Promise)) { + let maxLocation = StrCast(linkedFwdDocs[altKey ? 1 : 0].maximizeLocation, "inTab"); + DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, document => this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey ? 1 : 0]); + } + } + } } } - private _lastTap: number = 0; - _hitExpander = false; onPointerDown = (e: React.PointerEvent): void => { this._downX = e.clientX; this._downY = e.clientY; @@ -206,8 +298,8 @@ export class DocumentView extends DocComponent(Docu if (e.shiftKey && e.buttons === 1) { CollectionDockingView.Instance.StartOtherDrag([Doc.MakeAlias(this.props.Document)], e); e.stopPropagation(); - } else if (this.active) { - //e.stopPropagation(); // bcz: doing this will block click events from CollectionFreeFormDocumentView which are needed for iconifying,etc + } else { + if (this.active) e.stopPropagation(); // events stop at the lowest document that is active. document.removeEventListener("pointermove", this.onPointerMove); document.addEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); @@ -215,7 +307,7 @@ export class DocumentView extends DocComponent(Docu } } onPointerMove = (e: PointerEvent): void => { - if (!e.cancelBubble) { + if (!e.cancelBubble && this.active) { if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); @@ -234,32 +326,22 @@ export class DocumentView extends DocComponent(Docu this._lastTap = Date.now(); } - deleteClicked = (): void => { - this.props.removeDocument && this.props.removeDocument(this.props.Document); - } - fieldsClicked = (e: React.MouseEvent): void => { - let kvp = Docs.KVPDocument(this.props.Document, { title: this.props.Document.title + ".kvp", width: 300, height: 300 }); - CollectionDockingView.Instance.AddRightSplit(kvp); - } - makeButton = (e: React.MouseEvent): void => { - let doc = this.props.Document.proto ? this.props.Document.proto : this.props.Document; + deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); } + fieldsClicked = (): void => { this.props.addDocTab(Docs.KVPDocument(this.Document, { width: 300, height: 300 }), "onRight") }; + makeBtnClicked = (): void => { + let doc = Doc.GetProto(this.props.Document); doc.isButton = !BoolCast(doc.isButton, false); if (StrCast(doc.layout).indexOf("Formatted") !== -1) { // only need to freeze the dimensions of text boxes since they don't have a native width and height naturally if (doc.isButton && !doc.nativeWidth) { doc.nativeWidth = this.props.Document[WidthSym](); doc.nativeHeight = this.props.Document[HeightSym](); } else { - doc.nativeWidth = doc.nativeHeight = undefined; } } } - fullScreenClicked = (e: React.MouseEvent): void => { - const doc = Doc.MakeCopy(this.props.Document, false); - if (doc) { - CollectionDockingView.Instance.OpenFullScreen(doc); - } - ContextMenu.Instance.clearItems(); + fullScreenClicked = (): void => { + CollectionDockingView.Instance.OpenFullScreen(Doc.MakeCopy(this.props.Document, false)); SelectionManager.DeselectAll(); } @@ -332,7 +414,7 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document), icon: "caret-square-right" }); cm.addItem({ description: "Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); - cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeButton, icon: "concierge-bell" }); + cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); cm.addItem({ description: "Find aliases", event: async () => { const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index d3d765eed..7b642b299 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -102,7 +102,6 @@ export class FieldView extends React.Component { layoutKey={"layout"} ContainingCollectionView={this.props.ContainingCollectionView} parentActive={this.props.active} - toggleMinimized={emptyFunction} whenActiveChanged={this.props.whenActiveChanged} bringToFront={emptyFunction} /> ); -- cgit v1.2.3-70-g09d2 From 890a40ef8cc2efa7beea5722301b59ede5141238 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 30 May 2019 13:47:53 -0400 Subject: fixed context menus and tree view jitter. --- src/client/util/DragManager.ts | 4 +-- src/client/util/TooltipTextMenu.tsx | 2 +- src/client/views/ContextMenu.scss | 2 +- src/client/views/ContextMenuItem.tsx | 2 +- src/client/views/MainView.tsx | 6 ++-- .../views/collections/CollectionDockingView.tsx | 6 +++- .../views/collections/CollectionTreeView.scss | 6 +++- .../views/collections/CollectionTreeView.tsx | 33 +++++++++++++--------- src/client/views/collections/CollectionView.tsx | 30 +++++++------------- src/client/views/nodes/DocumentView.tsx | 31 ++++++++++++++------ src/client/views/nodes/FormattedTextBox.tsx | 25 +--------------- src/client/views/nodes/ImageBox.tsx | 11 ++++---- .../authentication/models/current_user_utils.ts | 20 ++++++------- 13 files changed, 85 insertions(+), 93 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 7f75a95f0..8f0cce095 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -26,7 +26,7 @@ export function SetupDrag(_reference: React.RefObject, docFunc: () // if (this.props.isSelected() || this.props.isTopMost) { if (e.button === 0) { e.stopPropagation(); - if (e.shiftKey) { + if (e.shiftKey && CollectionDockingView.Instance) { CollectionDockingView.Instance.StartOtherDrag([await docFunc()], e); } else { document.addEventListener("pointermove", onRowMove); @@ -264,7 +264,7 @@ export namespace DragManager { if (dragData instanceof DocumentDragData) { dragData.userDropAction = e.ctrlKey || e.altKey ? "alias" : undefined; } - if (e.shiftKey) { + if (e.shiftKey && CollectionDockingView.Instance) { AbortDrag(); CollectionDockingView.Instance.StartOtherDrag(docs, { pageX: e.pageX, diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index a1f80120f..5dd10f1bf 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -194,7 +194,7 @@ export class TooltipTextMenu { if (DocumentManager.Instance.getDocumentView(f)) { DocumentManager.Instance.getDocumentView(f)!.props.focus(f); } - else CollectionDockingView.Instance.AddRightSplit(f); + else if (CollectionDockingView.Instance) CollectionDockingView.Instance.AddRightSplit(f); } })); } diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 61ae69179..74acba615 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -22,7 +22,7 @@ color: $light-color; } -.subMenu-cont { +.contextMenu-subMenu-cont { position: absolute; display: flex; z-index: 1000; diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 63347e076..fcda0db89 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -56,7 +56,7 @@ export class ContextMenuItem extends React.Component { } else { let submenu = !this.overItem ? (null) : -
+
{this._items.map(prop => )}
; return ( diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 74dafadc4..a093ffdec 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -104,7 +104,9 @@ export class MainView extends React.Component { }, false); // drag event handler // click interactions for the context menu document.addEventListener("pointerdown", action(function (e: PointerEvent) { - if (!ContextMenu.Instance.intersects(e.pageX, e.pageY)) { + + const targets = document.elementsFromPoint(e.x, e.y); + if (targets && targets.length && targets[0].className.toString().indexOf("contextMenu") === -1) { ContextMenu.Instance.clearItems(); } }), true); @@ -163,7 +165,7 @@ export class MainView extends React.Component { } openNotifsCol = () => { - if (this._notifsCol) { + if (this._notifsCol && CollectionDockingView.Instance) { CollectionDockingView.Instance.AddRightSplit(this._notifsCol); } } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index b6076b5f7..dcc1bd95d 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -22,6 +22,7 @@ import { ParentDocSelector } from './ParentDocumentSelector'; import { DocumentManager } from '../../util/DocumentManager'; import { CollectionViewType } from './CollectionBaseView'; import { Id } from '../../../new_fields/FieldSymbols'; +import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; @observer export class CollectionDockingView extends React.Component { @@ -415,7 +416,10 @@ export class DockedFrameRenderer extends React.Component { @observable private _panelHeight = 0; @observable private _document: Opt; get _stack(): any { - return (this.props as any).glContainer.parent.parent; + let parent = (this.props as any).glContainer.parent.parent; + if (this._document && this._document.excludeFromLibrary && parent.parent && parent.parent.contentItems.length > 1) + return parent.parent.contentItems[1]; + return parent; } constructor(props: any) { super(props); diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 2f0329fc4..bb3be0a73 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -48,7 +48,11 @@ .treeViewItem-openRight { display: inline-block; // display: inline; - transform: translate(0px, -3px); //TODO Fix this + svg { + display:block; + padding:0px; + margin: 0px; + } } } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 85aab96d3..2814c0502 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -9,7 +9,7 @@ import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import React = require("react"); import { Document, listSpec } from '../../../new_fields/Schema'; -import { Cast, StrCast, BoolCast, FieldValue } from '../../../new_fields/Types'; +import { Cast, StrCast, BoolCast, FieldValue, NumCast } from '../../../new_fields/Types'; import { Doc, DocListCast } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { ContextMenu } from '../ContextMenu'; @@ -19,6 +19,7 @@ import { CollectionDockingView } from './CollectionDockingView'; import { DocumentManager } from '../../util/DocumentManager'; import { Docs } from '../../documents/Documents'; import { MainView } from '../MainView'; +import { CollectionViewType } from './CollectionBaseView'; export interface TreeViewProps { @@ -54,7 +55,7 @@ class TreeView extends React.Component { if (this.props.document.dockingConfig) { MainView.Instance.openWorkspace(this.props.document); } else { - CollectionDockingView.Instance.AddRightSplit(this.props.document); + this.props.addDocTab(this.props.document, "openRight"); } } @@ -122,11 +123,11 @@ class TreeView extends React.Component { return true; }} />); - let dataDocs = Cast(CollectionDockingView.Instance.props.Document.data, listSpec(Doc), []); + let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document.data, listSpec(Doc), []) : []; let openRight = dataDocs && dataDocs.indexOf(this.props.document) !== -1 ? (null) : (
- + {/* */}
); return (
{ } onWorkspaceContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.props.document)) }); - ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight") }); - ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.KVPDocument(this.props.document, { width: 300, height: 300 }), "onRight") }); - if (DocumentManager.Instance.getDocumentViews(this.props.document).length) { - ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.props.document).map(view => view.props.focus(this.props.document)) }); + ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.KVPDocument(this.props.document, { width: 300, height: 300 }), "onRight"), icon: "layer-group" }); + if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) { + ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, "inTab"), icon: "folder" }); + ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight"), icon: "caret-square-right" }); + if (DocumentManager.Instance.getDocumentViews(this.props.document).length) { + ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.props.document).map(view => view.props.focus(this.props.document)) }); + } + ContextMenu.Instance.addItem({ description: "Delete Item", event: undoBatch(() => this.props.deleteDoc(this.props.document)) }); + } else { + ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.props.deleteDoc(this.props.document)) }); } - ContextMenu.Instance.addItem({ description: "Delete", event: undoBatch(() => this.props.deleteDoc(this.props.document)) }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); e.stopPropagation(); } @@ -207,11 +213,10 @@ export class CollectionTreeView extends CollectionSubView(Document) { } } onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout + if (!e.isPropagationStopped() && this.props.Document.excludeFromLibrary) { // excludeFromLibrary means this is the user document ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => MainView.Instance.createNewWorkspace()) }); - } - if (!ContextMenu.Instance.getItems().some(item => item.description === "Delete")) { - ContextMenu.Instance.addItem({ description: "Delete", event: undoBatch(() => this.remove(this.props.Document)) }); + ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.remove(this.props.Document)) }); } } render() { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index a1e7c7c69..68eefab4c 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,20 +1,19 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faProjectDiagram, faSquare, faTh, faTree, faSignature, faThList } from '@fortawesome/free-solid-svg-icons'; +import { faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; import { observer } from "mobx-react"; import * as React from 'react'; import { Id } from '../../../new_fields/FieldSymbols'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from '../ContextMenuItem'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { CollectionBaseView, CollectionRenderProps, CollectionViewType } from './CollectionBaseView'; import { CollectionDockingView } from "./CollectionDockingView"; -import { CollectionSchemaView } from "./CollectionSchemaView"; -import { CollectionTreeView } from "./CollectionTreeView"; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionStackingView } from './CollectionStackingView'; -import { NumCast } from '../../../new_fields/Types'; -import { WidthSym, HeightSym } from '../../../new_fields/Doc'; +import { CollectionTreeView } from "./CollectionTreeView"; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -44,26 +43,17 @@ export class CollectionView extends React.Component { get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } // bcz: ? Why do we need to compare Id's? - freezeNativeDimensions = (e: React.MouseEvent): void => { - if (NumCast(this.props.Document.nativeWidth)) { - this.props.Document.proto!.nativeWidth = undefined; - this.props.Document.proto!.nativeHeight = undefined; - - } else { - this.props.Document.proto!.nativeWidth = this.props.Document[WidthSym](); - this.props.Document.proto!.nativeHeight = this.props.Document[HeightSym](); - } - } onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Freeform), icon: "signature" }); + let subItems: ContextMenuProps[] = []; + subItems.push({ description: "Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Freeform), icon: "signature" }); if (CollectionBaseView.InSafeMode()) { ContextMenu.Instance.addItem({ description: "Test Freeform", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Invalid), icon: "project-diagram" }); } - ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "th-list" }); - ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree), icon: "tree" }); - ContextMenu.Instance.addItem({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "th-list" }); - ContextMenu.Instance.addItem({ description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", event: this.freezeNativeDimensions, icon: "edit" }); + subItems.push({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "th-list" }); + subItems.push({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree), icon: "tree" }); + subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "th-list" }); + ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems }); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a16a52ac6..69691b6f3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -29,6 +29,7 @@ import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); import { Id, Copy } from '../../../new_fields/FieldSymbols'; +import { ContextMenuProps } from '../ContextMenuItem'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(faTrash); @@ -263,7 +264,7 @@ export class DocumentView extends DocComponent(Docu expandedProtoDocs.forEach(maxDoc => maxDoc.isMinimized = wasMinimized); } } - if (maxLocation && maxLocation !== "inPlace") { + if (maxLocation && maxLocation !== "inPlace" && CollectionDockingView.Instance) { let dataDocs = DocListCast(CollectionDockingView.Instance.props.Document.data); if (dataDocs) { expandedDocs.forEach(maxDoc => @@ -295,7 +296,7 @@ export class DocumentView extends DocComponent(Docu this._downX = e.clientX; this._downY = e.clientY; this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0; - if (e.shiftKey && e.buttons === 1) { + if (e.shiftKey && e.buttons === 1 && CollectionDockingView.Instance) { CollectionDockingView.Instance.StartOtherDrag([Doc.MakeAlias(this.props.Document)], e); e.stopPropagation(); } else { @@ -341,7 +342,7 @@ export class DocumentView extends DocComponent(Docu } } fullScreenClicked = (): void => { - CollectionDockingView.Instance.OpenFullScreen(Doc.MakeCopy(this.props.Document, false)); + CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(Doc.MakeCopy(this.props.Document, false)); SelectionManager.DeselectAll(); } @@ -398,6 +399,17 @@ export class DocumentView extends DocComponent(Docu this.templates = this.templates; } + freezeNativeDimensions = (e: React.MouseEvent): void => { + if (NumCast(this.props.Document.nativeWidth)) { + this.props.Document.proto!.nativeWidth = undefined; + this.props.Document.proto!.nativeHeight = undefined; + + } else { + this.props.Document.proto!.nativeWidth = this.props.Document[WidthSym](); + this.props.Document.proto!.nativeHeight = this.props.Document[HeightSym](); + } + } + @action onContextMenu = (e: React.MouseEvent): void => { e.stopPropagation(); @@ -409,16 +421,19 @@ export class DocumentView extends DocComponent(Docu e.preventDefault(); const cm = ContextMenu.Instance; - cm.addItem({ description: "Full Screen", event: this.fullScreenClicked, icon: "desktop" }); - cm.addItem({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "inTab"), icon: "folder" }); - cm.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document), icon: "caret-square-right" }); - cm.addItem({ description: "Fields", event: this.fieldsClicked, icon: "layer-group" }); + let subitems: ContextMenuProps[] = []; + subitems.push({ description: "Open Full Screen", event: this.fullScreenClicked, icon: "desktop" }); + subitems.push({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "inTab"), icon: "folder" }); + subitems.push({ description: "Open Right", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "onRight"), icon: "caret-square-right" }); + subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); + cm.addItem({ description: "Open...", subitems: subitems }); + cm.addItem({ description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", event: this.freezeNativeDimensions, icon: "edit" }); cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); cm.addItem({ description: "Find aliases", event: async () => { const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); - CollectionDockingView.Instance.AddRightSplit(Docs.SchemaDocument(["title"], aliases, {})); + this.props.addDocTab && this.props.addDocTab(Docs.SchemaDocument(["title"], aliases, {}), "onRight"); }, icon: "search" }); cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document), icon: "crosshairs" }); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index da584c811..5d93edaac 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -240,7 +240,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (DocumentManager.Instance.getDocumentView(f)) { DocumentManager.Instance.getDocumentView(f)!.props.focus(f); } else { - CollectionDockingView.Instance.AddRightSplit(f); + this.props.addDocTab && this.props.addDocTab(f, "onRight"); } } })); @@ -274,29 +274,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } } - - freezeNativeDimensions = (e: React.MouseEvent): void => { - if (NumCast(this.props.Document.nativeWidth)) { - this.props.Document.proto!.nativeWidth = undefined; - this.props.Document.proto!.nativeHeight = undefined; - - } else { - this.props.Document.proto!.nativeWidth = this.props.Document[WidthSym](); - this.props.Document.proto!.nativeHeight = this.props.Document[HeightSym](); - } - } - specificContextMenu = (e: React.MouseEvent): void => { - if (!this._gotDown) { - e.preventDefault(); - return; - } - ContextMenu.Instance.addItem({ - description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", - event: this.freezeNativeDimensions, - icon: "edit" - }); - } - onPointerWheel = (e: React.WheelEvent): void => { if (this.props.isSelected()) { e.stopPropagation(); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 8ea6c5436..4c2b73b70 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -19,6 +19,7 @@ import { InkingControl } from '../InkingControl'; import { Doc, WidthSym, HeightSym } from '../../../new_fields/Doc'; import { faImage } from '@fortawesome/free-solid-svg-icons'; import { library } from '@fortawesome/fontawesome-svg-core'; +import { ContextMenuItemProps, ContextMenuProps } from '../ContextMenuItem'; var path = require('path'); @@ -131,12 +132,9 @@ export class ImageBox extends DocComponent(ImageD let field = Cast(this.Document[this.props.fieldKey], ImageField); if (field) { let url = field.url.href; - ContextMenu.Instance.addItem({ - description: "Copy path", event: () => { - Utils.CopyText(url); - }, icon: "expand-arrows-alt" - }); - ContextMenu.Instance.addItem({ + let subitems: ContextMenuProps[] = []; + subitems.push({ description: "Copy path", event: () => Utils.CopyText(url), icon: "expand-arrows-alt" }); + subitems.push({ description: "Rotate", event: action(() => { this.props.Document.rotation = (NumCast(this.props.Document.rotation) + 90) % 360; let nw = this.props.Document.nativeWidth; @@ -147,6 +145,7 @@ export class ImageBox extends DocComponent(ImageD this.props.Document.height = w; }), icon: "expand-arrows-alt" }); + ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: subitems }); } } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index add347a88..e5b7a025b 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -1,21 +1,17 @@ -import { computed, observable, action, runInAction } from "mobx"; +import { action, computed, observable, runInAction } from "mobx"; import * as rp from 'request-promise'; +import { DocServer } from "../../../client/DocServer"; import { Docs } from "../../../client/documents/Documents"; -import { Attribute, AttributeGroup, Catalog, Schema, AggregateFunction } from "../../../client/northstar/model/idea/idea"; +import { Gateway, NorthstarSettings } from "../../../client/northstar/manager/Gateway"; +import { Attribute, AttributeGroup, Catalog, Schema } from "../../../client/northstar/model/idea/idea"; import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil"; -import { RouteStore } from "../../RouteStore"; -import { DocServer } from "../../../client/DocServer"; -import { Doc, Opt, Field } from "../../../new_fields/Doc"; -import { List } from "../../../new_fields/List"; import { CollectionViewType } from "../../../client/views/collections/CollectionBaseView"; -import { CollectionTreeView } from "../../../client/views/collections/CollectionTreeView"; import { CollectionView } from "../../../client/views/collections/CollectionView"; -import { NorthstarSettings, Gateway } from "../../../client/northstar/manager/Gateway"; -import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel"; -import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel"; -import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation"; -import { Cast, PromiseValue } from "../../../new_fields/Types"; +import { Doc } from "../../../new_fields/Doc"; +import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; +import { Cast } from "../../../new_fields/Types"; +import { RouteStore } from "../../RouteStore"; export class CurrentUserUtils { private static curr_email: string; -- cgit v1.2.3-70-g09d2 From e83c2a88303ae6d994a0ac2e84214947cac4d96d Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Fri, 31 May 2019 00:44:30 -0400 Subject: Added Open Tab Alias and Open Right Alias to context menu Cleaned up MakeAlias --- src/client/util/TooltipTextMenu.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 2 ++ src/new_fields/Doc.ts | 13 ++----------- 3 files changed, 5 insertions(+), 11 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 5dd10f1bf..f517f757a 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -198,6 +198,7 @@ export class TooltipTextMenu { } })); } + // TODO This should have an else to handle external links e.stopPropagation(); e.preventDefault(); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c7c142c3b..4905f0ddc 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -424,7 +424,9 @@ export class DocumentView extends DocComponent(Docu let subitems: ContextMenuProps[] = []; subitems.push({ description: "Open Full Screen", event: this.fullScreenClicked, icon: "desktop" }); subitems.push({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "inTab"), icon: "folder" }); + subitems.push({ description: "Open Tab Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), "inTab"), icon: "folder" }); subitems.push({ description: "Open Right", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "onRight"), icon: "caret-square-right" }); + subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Open...", subitems: subitems }); cm.addItem({ description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", event: this.freezeNativeDimensions, icon: "edit" }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 0c74b8f65..7f7263cf1 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -213,19 +213,10 @@ export namespace Doc { export function MakeAlias(doc: Doc) { - const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : undefined; const alias = new Doc; - - if (!proto) { - alias.proto = doc; - } else { - PromiseValue(Cast(doc.proto, Doc)).then(proto => { - if (proto) { - alias.proto = proto; - } - }); + if (!GetT(doc, "isPrototype", "boolean", true)) { + alias.proto = doc.proto; } - return alias; } -- cgit v1.2.3-70-g09d2 From d1b0f462ced168f3a9ac5d007ba1219e98a3b6cf Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 31 May 2019 18:18:05 -0400 Subject: stacking views and more.. --- src/client/views/MainOverlayTextBox.tsx | 11 +++++++-- .../views/collections/CollectionBaseView.tsx | 2 +- .../views/collections/CollectionStackingView.scss | 2 +- .../views/collections/CollectionStackingView.tsx | 28 +++++++++++++++------- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 13 ++++------ 6 files changed, 36 insertions(+), 22 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 6e8e6f8ce..24327b995 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -7,6 +7,8 @@ import { Transform } from '../util/Transform'; import "normalize.css"; import "./MainOverlayTextBox.scss"; import { FormattedTextBox } from './nodes/FormattedTextBox'; +import { CollectionDockingView } from './collections/CollectionDockingView'; +import { Doc } from '../../new_fields/Doc'; interface MainOverlayTextBoxProps { } @@ -82,6 +84,11 @@ export class MainOverlayTextBox extends React.Component document.removeEventListener('pointerup', this.textBoxUp); } + addDocTab = (doc: Doc, location: string) => { + if (true) { // location === "onRight") { need to figure out stack to add "inTab" + CollectionDockingView.Instance.AddRightSplit(doc); + } + } render() { if (FormattedTextBox.InputBoxOverlay && this._textTargetDiv) { let textRect = this._textTargetDiv.getBoundingClientRect(); @@ -91,10 +98,10 @@ export class MainOverlayTextBox extends React.Component style={{ width: `${textRect.width * s}px`, height: `${textRect.height * s}px` }}> + ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} />
; } - else return (null); + else return (null); Z } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index e89b8be0f..734669893 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -120,7 +120,7 @@ export class CollectionBaseView extends React.Component { // set the ZoomBasis only if hasn't already been set -- bcz: maybe set/resetting the ZoomBasis should be a parameter to addDocument? if (!alreadyAdded && (this.collectionViewType === CollectionViewType.Freeform || this.collectionViewType === CollectionViewType.Invalid)) { let zoom = NumCast(this.props.Document.scale, 1); - Doc.SetOnPrototype(doc, "zoomBasis", zoom); + // Doc.GetProto(doc).zoomBasis = zoom; } } return true; diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 1bb0b2674..1ab335cc3 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -6,7 +6,7 @@ display: flex; flex-direction: column; width: 100%; - height: 100%; + height: auto; position: absolute; overflow-y: auto; border-width: 0; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index bf246d4ec..a616b5ac7 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,24 +1,36 @@ import React = require("react"); +import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; -import { CollectionSubView, CollectionViewProps, SubCollectionViewProps } from "./CollectionSubView"; -import { Doc, WidthSym, HeightSym, DocListCast } from "../../../new_fields/Doc"; -import { DocumentView } from "../nodes/DocumentView"; -import { Transform } from "../../util/Transform"; +import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; +import { Id } from "../../../new_fields/FieldSymbols"; +import { NumCast } from "../../../new_fields/Types"; import { emptyFunction, returnOne, Utils } from "../../../Utils"; +import { DocumentView } from "../nodes/DocumentView"; import "./CollectionStackingView.scss"; -import { action, reaction, trace, computed } from "mobx"; -import { StrCast, NumCast } from "../../../new_fields/Types"; -import { Id } from "../../../new_fields/FieldSymbols"; +import { CollectionSubView } from "./CollectionSubView"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { _masonryGridRef: HTMLDivElement | null = null; + _heightDisposer?: IReactionDisposer; get gridGap() { return 10; } get gridSize() { return 20; } get itemWidth() { return NumCast(this.props.Document.itemWidth, 250); } + componentDidMount() { + this._heightDisposer = reaction(() => [this.childDocs.map(d => d[HeightSym]()), this.props.PanelWidth()], + () => { + let hgt = (this.props.PanelWidth() > 500) ? this.props.Document[HeightSym]() : + this.childDocs.filter(d => !d.isMinimized).reduce((height, d) => height + d[HeightSym]() + this.gridGap, this.gridGap + 20 /* top margin */); + this.props.Document.height = hgt; + }, { fireImmediately: true }); + } + componentWillUnmount() { + if (this._heightDisposer) this._heightDisposer(); + } + @action moveDocument = (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean): boolean => { this.props.removeDocument(doc); @@ -37,7 +49,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } @computed get children() { - return this.childDocs.map(d => { + return this.childDocs.filter(d => !d.isMinimized).map(d => { let colSpan = Math.ceil((this.itemWidth + this.gridGap) / (this.gridSize + this.gridGap)); let rowSpan = Math.ceil((this.itemWidth / d[WidthSym]() * d[HeightSym]() + this.gridGap) / (this.gridSize + this.gridGap)); let dref = React.createRef(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 69691b6f3..f3a596558 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -328,7 +328,7 @@ export class DocumentView extends DocComponent(Docu } deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); } - fieldsClicked = (): void => { this.props.addDocTab(Docs.KVPDocument(this.Document, { width: 300, height: 300 }), "onRight") }; + fieldsClicked = (): void => { this.props.addDocTab(Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight") }; makeBtnClicked = (): void => { let doc = Doc.GetProto(this.props.Document); doc.isButton = !BoolCast(doc.isButton, false); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 5d93edaac..3b61c68dd 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -230,20 +230,15 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._toolTipTextMenu.tooltip.style.opacity = "0"; } } + let ctrlKey = e.ctrlKey; if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey) { if (e.target && (e.target as any).href) { let href = (e.target as any).href; if (href.indexOf(DocServer.prepend("/doc/")) === 0) { let docid = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; - DocServer.GetRefField(docid).then(action((f: Opt) => { - if (f instanceof Doc) { - if (DocumentManager.Instance.getDocumentView(f)) { - DocumentManager.Instance.getDocumentView(f)!.props.focus(f); - } else { - this.props.addDocTab && this.props.addDocTab(f, "onRight"); - } - } - })); + DocServer.GetRefField(docid).then(f => { + (f instanceof Doc) && DocumentManager.Instance.jumpToDocument(f, ctrlKey, document => this.props.addDocTab(document, "inTab")) + }); } e.stopPropagation(); e.preventDefault(); -- cgit v1.2.3-70-g09d2 From 448996fbc234b82a27da952f85587a27cabe8881 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 1 Jun 2019 15:21:19 -0400 Subject: fixed stacking views to work with minimized documents --- .../views/collections/CollectionStackingView.tsx | 30 +++++++++++++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 42 +++++++++++++++++----- src/client/views/nodes/DocumentView.tsx | 30 ++-------------- 3 files changed, 62 insertions(+), 40 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a616b5ac7..d06413154 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -3,11 +3,14 @@ import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; -import { NumCast } from "../../../new_fields/Types"; +import { NumCast, Cast, BoolCast } from "../../../new_fields/Types"; import { emptyFunction, returnOne, Utils } from "../../../Utils"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; +import { undoBatch } from "../../util/UndoManager"; +import { SelectionManager } from "../../util/SelectionManager"; +import { List } from "../../../new_fields/List"; @@ -20,10 +23,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { get itemWidth() { return NumCast(this.props.Document.itemWidth, 250); } componentDidMount() { - this._heightDisposer = reaction(() => [this.childDocs.map(d => d[HeightSym]()), this.props.PanelWidth()], + this._heightDisposer = reaction(() => [this.childDocs.map(d => [d[HeightSym](), d.isMinimized]), this.props.PanelWidth()], () => { let hgt = (this.props.PanelWidth() > 500) ? this.props.Document[HeightSym]() : - this.childDocs.filter(d => !d.isMinimized).reduce((height, d) => height + d[HeightSym]() + this.gridGap, this.gridGap + 20 /* top margin */); + this.childDocs.filter(d => !d.isMinimized).reduce((height, d) => { + let rowSpan = Math.ceil((this.itemWidth / d[WidthSym]() * d[HeightSym]() + this.gridGap) / (this.gridSize + this.gridGap)); + return height + rowSpan * (this.gridSize + this.gridGap); + }, 10); this.props.Document.height = hgt; }, { fireImmediately: true }); } @@ -47,6 +53,20 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { this._masonryGridRef = ele; this.createDropTarget(ele!); } + @undoBatch + @action + public collapseToPoint = (scrpt: number[], expandedDocs: Doc[] | undefined): void => { + SelectionManager.DeselectAll(); + if (expandedDocs) { + let isMinimized: boolean | undefined; + expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => { + if (isMinimized === undefined) { + isMinimized = BoolCast(maximizedDoc.isMinimized, false); + } + maximizedDoc.isMinimized = !isMinimized; + }); + } + } @computed get children() { return this.childDocs.filter(d => !d.isMinimized).map(d => { @@ -84,7 +104,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { parentActive={this.props.active} addDocTab={this.props.addDocTab} bringToFront={emptyFunction} - whenActiveChanged={this.props.whenActiveChanged} /> + whenActiveChanged={this.props.whenActiveChanged} + collapseToPoint={this.collapseToPoint} + />
); }) } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 411e8c059..499b83c0f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,19 +1,17 @@ -import { action, computed, IReactionDisposer, reaction, trace } from "mobx"; +import { computed, IReactionDisposer, reaction, action } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; +import { Doc } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema"; -import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; -import { OmitKeys, Utils } from "../../../Utils"; -import { DocumentManager } from "../../util/DocumentManager"; -import { SelectionManager } from "../../util/SelectionManager"; +import { BoolCast, Cast, FieldValue, NumCast } from "../../../new_fields/Types"; +import { OmitKeys } from "../../../Utils"; import { Transform } from "../../util/Transform"; -import { UndoManager } from "../../util/UndoManager"; -import { CollectionDockingView } from "../collections/CollectionDockingView"; import { DocComponent } from "../DocComponent"; import { DocumentView, DocumentViewProps, positionSchema } from "./DocumentView"; import "./DocumentView.scss"; import React = require("react"); +import { UndoManager } from "../../util/UndoManager"; +import { SelectionManager } from "../../util/SelectionManager"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { } @@ -70,6 +68,7 @@ export class CollectionFreeFormDocumentView extends DocComponent; } @@ -88,6 +87,33 @@ export class CollectionFreeFormDocumentView extends DocComponent => { + SelectionManager.DeselectAll(); + if (expandedDocs) { + if (!CollectionFreeFormDocumentView._undoBatch) { + CollectionFreeFormDocumentView._undoBatch = UndoManager.StartBatch("iconAnimating"); + } + let isMinimized: boolean | undefined; + expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => { + let iconAnimating = Cast(maximizedDoc.isIconAnimating, List); + if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) { + if (isMinimized === undefined) { + isMinimized = BoolCast(maximizedDoc.isMinimized, false); + } + maximizedDoc.willMaximize = isMinimized; + maximizedDoc.isMinimized = false; + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]); + } + }); + setTimeout(() => { + CollectionFreeFormDocumentView._undoBatch && CollectionFreeFormDocumentView._undoBatch.end(); + CollectionFreeFormDocumentView._undoBatch = undefined; + }, 500); + } + } + animateBetweenIcon(first: boolean, icon: number[], targ: number[], width: number, height: number, stime: number, maximizing: boolean) { setTimeout(() => { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index be40efbfa..80c1292ae 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -75,7 +75,7 @@ export interface DocumentViewProps { whenActiveChanged: (isActive: boolean) => void; bringToFront: (doc: Doc) => void; addDocTab: (doc: Doc, where: string) => void; - whenClicked?: () => void; + collapseToPoint?: (scrpt: number[], expandedDocs: Doc[] | undefined) => void; } const schema = createSchema({ @@ -195,32 +195,6 @@ export class DocumentView extends DocComponent(Docu } } - static _undoBatch?: UndoManager.Batch = undefined; - @action - public collapseToPoint = async (scrpt: number[], expandedDocs: Doc[] | undefined): Promise => { - SelectionManager.DeselectAll(); - if (expandedDocs) { - if (!DocumentView._undoBatch) { - DocumentView._undoBatch = UndoManager.StartBatch("iconAnimating"); - } - let isMinimized: boolean | undefined; - expandedDocs.map(d => Doc.GetProto(d)).map(maximizedDoc => { - let iconAnimating = Cast(maximizedDoc.isIconAnimating, List); - if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) { - if (isMinimized === undefined) { - isMinimized = BoolCast(maximizedDoc.isMinimized, false); - } - maximizedDoc.willMaximize = isMinimized; - maximizedDoc.isMinimized = false; - maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]); - } - }); - setTimeout(() => { - DocumentView._undoBatch && DocumentView._undoBatch.end(); - DocumentView._undoBatch = undefined; - }, 500); - } - } onClick = async (e: React.MouseEvent) => { e.stopPropagation(); let altKey = e.altKey; @@ -273,7 +247,7 @@ export class DocumentView extends DocComponent(Docu } } else { let scrpt = this.props.ScreenToLocalTransform().inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2); - this.collapseToPoint(scrpt, expandedProtoDocs); + this.props.collapseToPoint && this.props.collapseToPoint(scrpt, expandedProtoDocs); } } else if (linkedToDocs.length || linkedFromDocs.length) { -- cgit v1.2.3-70-g09d2 From f4e6d81f4be7e26ec8866ea5a6e9d2433b89a79c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 2 Jun 2019 22:22:05 -0400 Subject: fixes to stacking view and freezing collections --- .../views/collections/CollectionStackingView.tsx | 21 +++++++++++---------- .../collections/collectionFreeForm/MarqueeView.tsx | 12 ++++++++---- src/client/views/nodes/DocumentView.tsx | 21 +++++++++++++++------ 3 files changed, 34 insertions(+), 20 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 25cc55be9..dcc7417ad 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -22,14 +22,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { get columnWidth() { return this.singleColumn ? this.props.PanelWidth() - 2 * this.gridSize - this.gridGap : NumCast(this.props.Document.columnWidth, 250); } componentDidMount() { - this._heightDisposer = reaction(() => [this.childDocs.map(d => [d[HeightSym](), d.isMinimized]), this.props.PanelHeight(), this.props.PanelWidth()], + this._heightDisposer = reaction(() => [this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized]), this.columnWidth, this.props.PanelHeight()], () => { if (this.singleColumn) { this.props.Document.height = this.childDocs.filter(d => !d.isMinimized).reduce((height, d) => { - let hgt = d[HeightSym](); + let hgt = d[HeightSym]() / NumCast(d.zoomBasis, 1); let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); - if (nw && nh) hgt = nh / nw * Math.min(this.columnWidth, d[WidthSym]()); + if (nw && nh) hgt = nh / nw * Math.min(this.columnWidth, d[WidthSym]() / NumCast(d.zoomBasis, 1)); let rowSpan = Math.ceil((hgt + this.gridGap) / (this.gridSize + this.gridGap)); return height + rowSpan * (this.gridSize + this.gridGap); }, 10); @@ -76,19 +76,20 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return this.childDocs.filter(d => !d.isMinimized).map(d => { let dref = React.createRef(); let script = undefined; - let colWidth = () => this.columnWidth; + let colWidth = () => d.nativeWidth ? Math.min(d[WidthSym]() / NumCast(d.zoomBasis, 1), this.columnWidth) : this.columnWidth; + let margin = colWidth() < this.columnWidth ? "auto" : undefined; let rowHeight = () => { - let hgt = d[HeightSym](); + let hgt = d[HeightSym]() / NumCast(d.zoomBasis, 1); let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); - if (nw && nh) hgt = nh / nw * Math.min(this.columnWidth, d[WidthSym]()); + if (nw && nh) hgt = nh / nw * colWidth(); return hgt; } let dxf = () => this.getDocTransform(d, dref.current!).scale(this.columnWidth / d[WidthSym]()); return
+ style={{ width: colWidth(), height: rowHeight(), marginLeft: margin, marginRight: margin }} > doc) { return this.childDocs.filter(d => !d.isMinimized).map(d => { let dref = React.createRef(); let dxf = () => this.getDocTransform(d, dref.current!); - let colSpan = Math.ceil((this.columnWidth + this.gridGap) / (this.gridSize + this.gridGap)); + let colSpan = Math.ceil(Math.min(d[WidthSym](), this.columnWidth + this.gridGap) / (this.gridSize + this.gridGap)); let rowSpan = Math.ceil((this.columnWidth / d[WidthSym]() * d[HeightSym]() + this.gridGap) / (this.gridSize + this.gridGap)); let childFocus = (doc: Doc) => { doc.libraryBrush = true; this.props.focus(this.props.Document); // just focus on this collection, not the underlying document because the API doesn't support adding an offset to focus on and we can't pan zoom our contents to be centered. } - return (
doc) { width: `${cells * itemCols * (this.gridSize + this.gridGap) + leftMargin}`, height: "100%", overflow: "hidden", - marginLeft: "auto", marginRight: "auto", position: "relative", + marginRight: "auto", position: "relative", gridGap: this.gridGap, gridTemplateColumns: this.singleColumn ? undefined : `repeat(auto-fill, minmax(${this.gridSize}px,1fr))`, gridAutoRows: this.singleColumn ? undefined : `${this.gridSize}px` diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 14dbe1899..a19f40978 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -20,6 +20,8 @@ import { Template, Templates } from "../../Templates"; import { SearchBox } from "../../SearchBox"; import { DocServer } from "../../../DocServer"; import { Id } from "../../../../new_fields/FieldSymbols"; +import { CollectionView } from "../CollectionView"; +import { CollectionViewType } from "../CollectionBaseView"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -284,10 +286,12 @@ export class MarqueeView extends React.Component newCollection.proto!.summaryDoc = summary; selected = [newCollection]; newCollection.x = bounds.left + bounds.width; - summary.proto!.summarizedDocs = new List(selected); - summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight" - - this.props.addLiveTextDocument(summary); + summary.proto!.subBulletDocs = new List(selected); + //summary.proto!.maximizeLocation = "inTab"; // or "inPlace", or "onRight" + summary.templates = new List([Templates.Bullet.Layout]); + let container = Docs.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, title: "-summary-" }); + container.viewType = CollectionViewType.Stacking; + this.props.addLiveTextDocument(container); // }); } else if (e.key === "S") { await htmlToImage.toPng(this._mainCont.current!, { width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, quality: 0.2 }).then((dataUrl) => { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 80c1292ae..b9e000ec8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -375,12 +375,21 @@ export class DocumentView extends DocComponent(Docu freezeNativeDimensions = (e: React.MouseEvent): void => { if (NumCast(this.props.Document.nativeWidth)) { - this.props.Document.proto!.nativeWidth = undefined; - this.props.Document.proto!.nativeHeight = undefined; - - } else { - this.props.Document.proto!.nativeWidth = this.props.Document[WidthSym](); - this.props.Document.proto!.nativeHeight = this.props.Document[HeightSym](); + let proto = Doc.GetProto(this.props.Document); + let nw = proto.nativeWidth; + let nh = proto.nativeHeight; + proto.nativeWidth = proto.nativeHeight = undefined; + this.props.Document.width = this.props.Document.frozenWidth; + this.props.Document.height = this.props.Document.frozenHeight; + } + else { + let scale = this.props.ScreenToLocalTransform().Scale * NumCast(this.props.Document.zoomBasis, 1); + let scr = this.screenRect(); + let proto = Doc.GetProto(this.props.Document); + this.props.Document.frozenWidth = this.props.Document.width; + this.props.Document.frozenHeight = this.props.Document.height; + this.props.Document.height = proto.nativeHeight = scr.height * scale; + this.props.Document.width = proto.nativeWidth = scr.width * scale; } } -- cgit v1.2.3-70-g09d2 From eccf79cb6e7abe2dd0555054e57d5037465c0bd2 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 4 Jun 2019 09:06:33 -0400 Subject: fix for stackingview with zoombasis. fix for text box links w/ styles --- src/client/views/collections/CollectionStackingView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index ea3c144f2..acd585268 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -32,7 +32,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let nh = NumCast(d.nativeHeight); if (nw && nh) hgt = nh / nw * Math.min(this.columnWidth, wid); return height + hgt + 2 * this.gridGap; - }, this.gridGap * 2); + }, this.gridGap * 2) * NumCast(this.props.Document.zoomBasis, 1); } }, { fireImmediately: true }); } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 3b61c68dd..5c635cc0c 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -231,9 +231,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } let ctrlKey = e.ctrlKey; - if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey) { - if (e.target && (e.target as any).href) { - let href = (e.target as any).href; + if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) { + let href = (e.target as any).href; + for (let parent = (e.target as any).parentNode; !href && parent; parent = parent.parentNode) { + href = parent.childNodes[0].href; + } + if (href) { if (href.indexOf(DocServer.prepend("/doc/")) === 0) { let docid = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; DocServer.GetRefField(docid).then(f => { -- cgit v1.2.3-70-g09d2 From 6f49d067b58caf6297f7ae7687cf05b627c27a1d Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 4 Jun 2019 09:48:18 -0400 Subject: icon and stacking view fixes. --- src/client/util/DragManager.ts | 3 +-- src/client/views/collections/CollectionStackingView.tsx | 10 +++++----- src/client/views/nodes/DocumentView.tsx | 4 ++-- src/client/views/nodes/IconBox.scss | 1 + 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 8f0cce095..1e84a0db0 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -279,8 +279,7 @@ export namespace DragManager { lastX = e.pageX; lastY = e.pageY; dragElements.map((dragElement, i) => (dragElement.style.transform = - `translate(${(xs[i] += moveX)}px, ${(ys[i] += moveY)}px) - scale(${scaleXs[i]}, ${scaleYs[i]})`) + `translate(${(xs[i] += moveX)}px, ${(ys[i] += moveY)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`) ); }; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index acd585268..da7ea50c6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -26,13 +26,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { () => { if (this.singleColumn) { this.props.Document.height = this.childDocs.filter(d => !d.isMinimized).reduce((height, d) => { - let hgt = d[HeightSym]() / NumCast(d.zoomBasis, 1); - let wid = d[WidthSym]() / NumCast(d.zoomBasis, 1); + let hgt = d[HeightSym](); + let wid = d[WidthSym](); let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); if (nw && nh) hgt = nh / nw * Math.min(this.columnWidth, wid); return height + hgt + 2 * this.gridGap; - }, this.gridGap * 2) * NumCast(this.props.Document.zoomBasis, 1); + }, this.gridGap * 2); } }, { fireImmediately: true }); } @@ -76,10 +76,10 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return this.childDocs.filter(d => !d.isMinimized).map((d, i) => { let dref = React.createRef(); let script = undefined; - let colWidth = () => d.nativeWidth ? Math.min(d[WidthSym]() / NumCast(d.zoomBasis, 1), this.columnWidth) : this.columnWidth; + let colWidth = () => d.nativeWidth ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth; let margin = colWidth() < this.columnWidth ? "auto" : undefined; let rowHeight = () => { - let hgt = d[HeightSym]() / NumCast(d.zoomBasis, 1); + let hgt = d[HeightSym](); let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); if (nw && nh) hgt = nh / nw * colWidth(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b9e000ec8..7750b9173 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -191,7 +191,7 @@ export class DocumentView extends DocComponent(Docu if (minimizedDoc) { let scrpt = this.props.ScreenToLocalTransform().inverse().transformPoint( NumCast(minimizedDoc.x) - NumCast(this.Document.x), NumCast(minimizedDoc.y) - NumCast(this.Document.y)); - this.collapseToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs)); + this.props.collapseToPoint && this.props.collapseToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs)); } } @@ -447,7 +447,7 @@ export class DocumentView extends DocComponent(Docu render() { var scaling = this.props.ContentScaling(); - var nativeHeight = this.nativeHeight > 0 ? `${this.nativeHeight}px` : (StrCast(this.props.Document.layout).indexOf("IconBox") === -1 ? "100%" : "auto"); + var nativeHeight = this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; var nativeWidth = this.nativeWidth > 0 ? `${this.nativeWidth}px` : "100%"; return ( diff --git a/src/client/views/nodes/IconBox.scss b/src/client/views/nodes/IconBox.scss index 893dc2d36..488681027 100644 --- a/src/client/views/nodes/IconBox.scss +++ b/src/client/views/nodes/IconBox.scss @@ -10,6 +10,7 @@ pointer-events: all; svg { width: $MINIMIZED_ICON_SIZE !important; + height: $MINIMIZED_ICON_SIZE !important; height: auto; background: white; } -- cgit v1.2.3-70-g09d2 From a37faf30652c6c593923198ad34e54377e670caf Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 5 Jun 2019 08:09:10 -0400 Subject: fixed full screen text bug. cleaned up imports --- src/client/views/DocumentDecorations.tsx | 33 +++++++++++----------- src/client/views/InkingControl.tsx | 1 - src/client/views/PresentationView.tsx | 16 +++++------ src/client/views/SearchItem.tsx | 8 ++---- src/client/views/TemplateMenu.tsx | 11 ++++---- .../views/collections/CollectionBaseView.tsx | 12 ++++---- .../views/collections/CollectionDockingView.tsx | 15 +++++----- .../views/collections/CollectionSchemaView.tsx | 1 - src/client/views/collections/CollectionSubView.tsx | 31 ++++++++++---------- .../views/collections/CollectionTreeView.tsx | 26 ++++++++--------- .../CollectionFreeFormLinkView.tsx | 7 ++--- .../CollectionFreeFormLinksView.tsx | 14 ++++----- .../CollectionFreeFormRemoteCursors.tsx | 12 ++++---- .../collectionFreeForm/CollectionFreeFormView.tsx | 20 ++++++------- .../collections/collectionFreeForm/MarqueeView.tsx | 26 ++++++++--------- src/client/views/nodes/FieldView.tsx | 29 +++++++++---------- src/client/views/nodes/FormattedTextBox.tsx | 6 ++-- src/client/views/nodes/ImageBox.tsx | 24 ++++++++-------- src/client/views/nodes/VideoBox.tsx | 16 +++++------ src/client/views/nodes/WebBox.tsx | 9 +++--- 20 files changed, 147 insertions(+), 170 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index da9b1253e..37895516a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,33 +1,32 @@ -import { action, computed, observable, runInAction, untracked, reaction } from "mobx"; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faLink } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, computed, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; +import { Doc } from "../../new_fields/Doc"; +import { List } from "../../new_fields/List"; +import { listSpec } from "../../new_fields/Schema"; +import { Cast, NumCast, StrCast } from "../../new_fields/Types"; import { emptyFunction, Utils } from "../../Utils"; +import { Docs } from "../documents/Documents"; +import { DocumentManager } from "../util/DocumentManager"; import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; import { undoBatch } from "../util/UndoManager"; +import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; +import { CollectionView } from "./collections/CollectionView"; import './DocumentDecorations.scss'; import { DocumentView, PositionDocument } from "./nodes/DocumentView"; +import { FieldView } from "./nodes/FieldView"; +import { FormattedTextBox } from "./nodes/FormattedTextBox"; +import { IconBox } from "./nodes/IconBox"; import { LinkMenu } from "./nodes/LinkMenu"; import { TemplateMenu } from "./TemplateMenu"; -import React = require("react"); import { Template, Templates } from "./Templates"; -import { CompileScript } from "../util/Scripting"; -import { IconBox } from "./nodes/IconBox"; -import { Cast, FieldValue, NumCast, StrCast } from "../../new_fields/Types"; -import { Doc, FieldResult } from "../../new_fields/Doc"; -import { listSpec } from "../../new_fields/Schema"; -import { Docs } from "../documents/Documents"; -import { List } from "../../new_fields/List"; +import React = require("react"); const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; -import { faLink } from '@fortawesome/free-solid-svg-icons'; -import { library } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; -import { CollectionView } from "./collections/CollectionView"; -import { DocumentManager } from "../util/DocumentManager"; -import { FormattedTextBox } from "./nodes/FormattedTextBox"; -import { FieldView } from "./nodes/FieldView"; library.add(faLink); diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index d456f531f..d1a6eb7fd 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -1,5 +1,4 @@ import { observable, action, computed } from "mobx"; - import { CirclePicker, ColorResult } from 'react-color'; import React = require("react"); import { observer } from "mobx-react"; diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index 9d5798ff1..b0c93ee26 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -1,15 +1,13 @@ +import { action, observable } from "mobx"; import { observer } from "mobx-react"; -import React = require("react"); -import { observable, action, runInAction, reaction } from "mobx"; -import "./PresentationView.scss"; -import { DocumentManager } from "../util/DocumentManager"; -import { Utils } from "../../Utils"; -import { Doc, DocListCast, DocListCastAsync } from "../../new_fields/Doc"; -import { listSpec } from "../../new_fields/Schema"; -import { Cast, NumCast, FieldValue, PromiseValue, StrCast, BoolCast } from "../../new_fields/Types"; +import { Doc, DocListCast } from "../../new_fields/Doc"; import { Id } from "../../new_fields/FieldSymbols"; import { List } from "../../new_fields/List"; -import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { listSpec } from "../../new_fields/Schema"; +import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../new_fields/Types"; +import { DocumentManager } from "../util/DocumentManager"; +import "./PresentationView.scss"; +import React = require("react"); export interface PresViewProps { Document: Doc; diff --git a/src/client/views/SearchItem.tsx b/src/client/views/SearchItem.tsx index 01c7316d6..6901f60da 100644 --- a/src/client/views/SearchItem.tsx +++ b/src/client/views/SearchItem.tsx @@ -1,13 +1,9 @@ import React = require("react"); -import { Doc } from "../../new_fields/Doc"; -import { DocumentManager } from "../util/DocumentManager"; import { library } from '@fortawesome/fontawesome-svg-core'; import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Cast } from "../../new_fields/Types"; -import { FieldView, FieldViewProps } from './nodes/FieldView'; -import { computed } from "mobx"; -import { IconField } from "../../new_fields/IconField"; +import { Doc } from "../../new_fields/Doc"; +import { DocumentManager } from "../util/DocumentManager"; import { SetupDrag } from "../util/DragManager"; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index e5b679e24..3288abd90 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -1,12 +1,11 @@ -import { observable, computed, action, trace } from "mobx"; -import React = require("react"); +import { action, observable } from "mobx"; import { observer } from "mobx-react"; +import { Doc } from "../../new_fields/Doc"; +import { List } from "../../new_fields/List"; import './DocumentDecorations.scss'; -import { Template } from "./Templates"; import { DocumentView } from "./nodes/DocumentView"; -import { List } from "../../new_fields/List"; -import { Doc } from "../../new_fields/Doc"; -import { NumCast } from "../../new_fields/Types"; +import { Template } from "./Templates"; +import React = require("react"); const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 734669893..9350dc974 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -1,14 +1,14 @@ import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { ContextMenu } from '../ContextMenu'; -import { FieldViewProps } from '../nodes/FieldView'; -import { Cast, FieldValue, PromiseValue, NumCast } from '../../../new_fields/Types'; -import { Doc, FieldResult, Opt, DocListCast } from '../../../new_fields/Doc'; -import { listSpec } from '../../../new_fields/Schema'; +import { Doc, DocListCast, Opt } from '../../../new_fields/Doc'; +import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; +import { listSpec } from '../../../new_fields/Schema'; +import { Cast, FieldValue, NumCast, PromiseValue } from '../../../new_fields/Types'; import { SelectionManager } from '../../util/SelectionManager'; -import { Id } from '../../../new_fields/FieldSymbols'; +import { ContextMenu } from '../ContextMenu'; +import { FieldViewProps } from '../nodes/FieldView'; export enum CollectionViewType { Invalid, diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index dcc1bd95d..8f6c9b1fc 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -1,28 +1,28 @@ import 'golden-layout/src/css/goldenlayout-base.css'; import 'golden-layout/src/css/goldenlayout-dark-theme.css'; -import { action, observable, reaction, Lambda } from "mobx"; +import { action, Lambda, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; import * as GoldenLayout from "../../../client/goldenLayout"; -import { Doc, Field, Opt, DocListCast } from "../../../new_fields/Doc"; +import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc"; +import { Id } from '../../../new_fields/FieldSymbols'; import { FieldId } from "../../../new_fields/RefField"; import { listSpec } from "../../../new_fields/Schema"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { emptyFunction, returnTrue, Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; +import { DocumentManager } from '../../util/DocumentManager'; import { DragLinksAsDocuments, DragManager } from "../../util/DragManager"; +import { SelectionManager } from '../../util/SelectionManager'; import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; +import { CollectionViewType } from './CollectionBaseView'; import "./CollectionDockingView.scss"; import { SubCollectionViewProps } from "./CollectionSubView"; -import React = require("react"); import { ParentDocSelector } from './ParentDocumentSelector'; -import { DocumentManager } from '../../util/DocumentManager'; -import { CollectionViewType } from './CollectionBaseView'; -import { Id } from '../../../new_fields/FieldSymbols'; -import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; +import React = require("react"); @observer export class CollectionDockingView extends React.Component { @@ -357,6 +357,7 @@ export class CollectionDockingView extends React.Component; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index be37efd3d..31e662da5 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,23 +1,22 @@ -import { action, runInAction } from "mobx"; -import React = require("react"); -import { undoBatch, UndoManager } from "../../util/UndoManager"; -import { DragManager } from "../../util/DragManager"; -import { Docs, DocumentOptions } from "../../documents/Documents"; -import { RouteStore } from "../../../server/RouteStore"; +import { action } from "mobx"; +import * as rp from 'request-promise'; +import CursorField from "../../../new_fields/CursorField"; +import { Doc, DocListCast, Opt } from "../../../new_fields/Doc"; +import { List } from "../../../new_fields/List"; +import { listSpec } from "../../../new_fields/Schema"; +import { Cast, PromiseValue } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; +import { RouteStore } from "../../../server/RouteStore"; +import { DocServer } from "../../DocServer"; +import { Docs, DocumentOptions } from "../../documents/Documents"; +import { DragManager } from "../../util/DragManager"; +import { undoBatch, UndoManager } from "../../util/UndoManager"; +import { DocComponent } from "../DocComponent"; import { FieldViewProps } from "../nodes/FieldView"; -import * as rp from 'request-promise'; -import { CollectionView } from "./CollectionView"; import { CollectionPDFView } from "./CollectionPDFView"; import { CollectionVideoView } from "./CollectionVideoView"; -import { Doc, Opt, FieldResult, DocListCast } from "../../../new_fields/Doc"; -import { DocComponent } from "../DocComponent"; -import { listSpec } from "../../../new_fields/Schema"; -import { Cast, PromiseValue, FieldValue, ListSpec } from "../../../new_fields/Types"; -import { List } from "../../../new_fields/List"; -import { DocServer } from "../../DocServer"; -import CursorField from "../../../new_fields/CursorField"; -import { DocumentManager } from "../../util/DocumentManager"; +import { CollectionView } from "./CollectionView"; +import React = require("react"); export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 48da52ffa..9fb1da716 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,25 +1,24 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; -import { faCaretDown, faCaretRight, faTrashAlt, faAngleRight } from '@fortawesome/free-solid-svg-icons'; +import { faAngleRight, faCaretDown, faCaretRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable, trace } from "mobx"; import { observer } from "mobx-react"; -import { DragManager, SetupDrag, dropActionType } from "../../util/DragManager"; -import { EditableView } from "../EditableView"; -import { CollectionSubView } from "./CollectionSubView"; -import "./CollectionTreeView.scss"; -import React = require("react"); -import { Document, listSpec } from '../../../new_fields/Schema'; -import { Cast, StrCast, BoolCast, FieldValue, NumCast } from '../../../new_fields/Types'; import { Doc, DocListCast } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; -import { ContextMenu } from '../ContextMenu'; -import { undoBatch } from '../../util/UndoManager'; -import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; -import { CollectionDockingView } from './CollectionDockingView'; -import { DocumentManager } from '../../util/DocumentManager'; +import { Document, listSpec } from '../../../new_fields/Schema'; +import { BoolCast, Cast, NumCast, StrCast } from '../../../new_fields/Types'; import { Docs } from '../../documents/Documents'; +import { DocumentManager } from '../../util/DocumentManager'; +import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager"; +import { undoBatch } from '../../util/UndoManager'; +import { ContextMenu } from '../ContextMenu'; +import { EditableView } from "../EditableView"; import { MainView } from '../MainView'; import { CollectionViewType } from './CollectionBaseView'; +import { CollectionDockingView } from './CollectionDockingView'; +import { CollectionSubView } from "./CollectionSubView"; +import "./CollectionTreeView.scss"; +import React = require("react"); export interface TreeViewProps { @@ -220,6 +219,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { } } render() { + trace(); let dropAction = StrCast(this.props.Document.dropAction, "alias") as dropActionType; if (!this.childDocs) { return (null); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 301b769af..ca7c99f28 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -1,11 +1,10 @@ import { observer } from "mobx-react"; -import { Utils } from "../../../../Utils"; +import { Doc, HeightSym, WidthSym } from "../../../../new_fields/Doc"; +import { BoolCast, NumCast, StrCast } from "../../../../new_fields/Types"; +import { InkingControl } from "../../InkingControl"; import "./CollectionFreeFormLinkView.scss"; import React = require("react"); import v5 = require("uuid/v5"); -import { StrCast, NumCast, BoolCast } from "../../../../new_fields/Types"; -import { Doc, WidthSym, HeightSym } from "../../../../new_fields/Doc"; -import { InkingControl } from "../../InkingControl"; export interface CollectionFreeFormLinkViewProps { A: Doc; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index a43c5f241..c4dd534ed 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,17 +1,16 @@ -import { computed, IReactionDisposer, reaction, trace } from "mobx"; +import { computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; -import { Utils } from "../../../../Utils"; +import { Doc, DocListCast } from "../../../../new_fields/Doc"; +import { Id } from "../../../../new_fields/FieldSymbols"; +import { List } from "../../../../new_fields/List"; +import { listSpec } from "../../../../new_fields/Schema"; +import { Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types"; import { DocumentManager } from "../../../util/DocumentManager"; import { DocumentView } from "../../nodes/DocumentView"; import { CollectionViewProps } from "../CollectionSubView"; import "./CollectionFreeFormLinksView.scss"; import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); -import { Doc, DocListCastAsync, DocListCast } from "../../../../new_fields/Doc"; -import { Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types"; -import { listSpec } from "../../../../new_fields/Schema"; -import { List } from "../../../../new_fields/List"; -import { Id } from "../../../../new_fields/FieldSymbols"; @observer export class CollectionFreeFormLinksView extends React.Component { @@ -110,7 +109,6 @@ export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9d19df540..2b43c76c6 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,8 +1,15 @@ -import { action, computed, trace } from "mobx"; +import { action, computed } from "mobx"; import { observer } from "mobx-react"; -import { emptyFunction, returnFalse, returnOne } from "../../../../Utils"; +import { Doc, HeightSym, WidthSym } from "../../../../new_fields/Doc"; +import { Id } from "../../../../new_fields/FieldSymbols"; +import { InkField, StrokeData } from "../../../../new_fields/InkField"; +import { createSchema, makeInterface } from "../../../../new_fields/Schema"; +import { BoolCast, Cast, FieldValue, NumCast } from "../../../../new_fields/Types"; +import { emptyFunction, returnOne } from "../../../../Utils"; +import { DocServer } from "../../../DocServer"; import { DocumentManager } from "../../../util/DocumentManager"; import { DragManager } from "../../../util/DragManager"; +import { HistoryUtil } from "../../../util/History"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; import { undoBatch } from "../../../util/UndoManager"; @@ -11,6 +18,7 @@ import { InkingCanvas } from "../../InkingCanvas"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "../../nodes/DocumentContentsView"; import { DocumentViewProps, positionSchema } from "../../nodes/DocumentView"; +import { pageSchema } from "../../nodes/ImageBox"; import { CollectionSubView } from "../CollectionSubView"; import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; @@ -18,14 +26,6 @@ import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); -import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; -import { Doc, WidthSym, HeightSym } from "../../../../new_fields/Doc"; -import { FieldValue, Cast, NumCast, BoolCast } from "../../../../new_fields/Types"; -import { pageSchema } from "../../nodes/ImageBox"; -import { InkField, StrokeData } from "../../../../new_fields/InkField"; -import { HistoryUtil } from "../../../util/History"; -import { Id } from "../../../../new_fields/FieldSymbols"; -import { DocServer } from "../../../DocServer"; export const panZoomSchema = createSchema({ panX: "number", diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 29734fa19..9ec941eff 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,27 +1,25 @@ import * as htmlToImage from "html-to-image"; -import { action, computed, observable, trace } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; +import { Doc } from "../../../../new_fields/Doc"; +import { Id } from "../../../../new_fields/FieldSymbols"; +import { InkField, StrokeData } from "../../../../new_fields/InkField"; +import { List } from "../../../../new_fields/List"; +import { Cast, NumCast } from "../../../../new_fields/Types"; +import { Utils } from "../../../../Utils"; +import { DocServer } from "../../../DocServer"; import { Docs } from "../../../documents/Documents"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; -import { undoBatch, UndoManager } from "../../../util/UndoManager"; +import { undoBatch } from "../../../util/UndoManager"; import { InkingCanvas } from "../../InkingCanvas"; import { PreviewCursor } from "../../PreviewCursor"; +import { SearchBox } from "../../SearchBox"; +import { Templates } from "../../Templates"; +import { CollectionViewType } from "../CollectionBaseView"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; import "./MarqueeView.scss"; import React = require("react"); -import { Utils } from "../../../../Utils"; -import { Doc } from "../../../../new_fields/Doc"; -import { NumCast, Cast } from "../../../../new_fields/Types"; -import { InkField, StrokeData } from "../../../../new_fields/InkField"; -import { List } from "../../../../new_fields/List"; -import { ImageField } from "../../../../new_fields/URLField"; -import { Template, Templates } from "../../Templates"; -import { SearchBox } from "../../SearchBox"; -import { DocServer } from "../../../DocServer"; -import { Id } from "../../../../new_fields/FieldSymbols"; -import { CollectionView } from "../CollectionView"; -import { CollectionViewType } from "../CollectionBaseView"; interface MarqueeViewProps { getContainerTransform: () => Transform; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 7b642b299..5a83de8e3 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,24 +1,23 @@ import React = require("react"); +import { computed } from "mobx"; import { observer } from "mobx-react"; -import { computed, observable } from "mobx"; -import { FormattedTextBox } from "./FormattedTextBox"; -import { ImageBox } from "./ImageBox"; -import { VideoBox } from "./VideoBox"; -import { AudioBox } from "./AudioBox"; -import { DocumentContentsView } from "./DocumentContentsView"; +import { DateField } from "../../../new_fields/DateField"; +import { Doc, FieldResult, Opt } from "../../../new_fields/Doc"; +import { IconField } from "../../../new_fields/IconField"; +import { List } from "../../../new_fields/List"; +import { RichTextField } from "../../../new_fields/RichTextField"; +import { AudioField, ImageField, VideoField } from "../../../new_fields/URLField"; +import { emptyFunction, returnFalse, returnOne } from "../../../Utils"; import { Transform } from "../../util/Transform"; -import { returnFalse, emptyFunction, returnOne } from "../../../Utils"; -import { CollectionView } from "../collections/CollectionView"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; +import { CollectionView } from "../collections/CollectionView"; +import { AudioBox } from "./AudioBox"; +import { DocumentContentsView } from "./DocumentContentsView"; +import { FormattedTextBox } from "./FormattedTextBox"; import { IconBox } from "./IconBox"; -import { Opt, Doc, FieldResult } from "../../../new_fields/Doc"; -import { List } from "../../../new_fields/List"; -import { ImageField, VideoField, AudioField } from "../../../new_fields/URLField"; -import { IconField } from "../../../new_fields/IconField"; -import { RichTextField } from "../../../new_fields/RichTextField"; -import { DateField } from "../../../new_fields/DateField"; -import { NumCast } from "../../../new_fields/Types"; +import { ImageBox } from "./ImageBox"; +import { VideoBox } from "./VideoBox"; // diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 5c635cc0c..53ab7c35e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -7,11 +7,12 @@ import { history } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { EditorState, Plugin, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; -import { Doc, Field, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc"; +import { Doc, Opt } from "../../../new_fields/Doc"; import { RichTextField } from "../../../new_fields/RichTextField"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { DocServer } from "../../DocServer"; +import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; import buildKeymap from "../../util/ProsemirrorKeymap"; @@ -21,14 +22,11 @@ import { SelectionManager } from "../../util/SelectionManager"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; import { undoBatch, UndoManager } from "../../util/UndoManager"; -import { ContextMenu } from "../../views/ContextMenu"; -import { CollectionDockingView } from "../collections/CollectionDockingView"; import { DocComponent } from "../DocComponent"; import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); -import { DocUtils } from '../../documents/Documents'; library.add(faEdit); library.add(faSmile); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 4c2b73b70..06ecc794b 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,25 +1,25 @@ -import { action, observable, trace } from 'mobx'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faImage } from '@fortawesome/free-solid-svg-icons'; +import { action, observable } from 'mobx'; import { observer } from "mobx-react"; import Lightbox from 'react-image-lightbox'; import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app +import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc'; +import { List } from '../../../new_fields/List'; +import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; +import { Cast, FieldValue, NumCast, StrCast } from '../../../new_fields/Types'; +import { ImageField } from '../../../new_fields/URLField'; import { Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../../views/ContextMenu"; +import { ContextMenuProps } from '../ContextMenuItem'; +import { DocComponent } from '../DocComponent'; +import { InkingControl } from '../InkingControl'; +import { positionSchema } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import React = require("react"); -import { createSchema, makeInterface, listSpec } from '../../../new_fields/Schema'; -import { DocComponent } from '../DocComponent'; -import { positionSchema } from './DocumentView'; -import { FieldValue, Cast, StrCast, PromiseValue, NumCast } from '../../../new_fields/Types'; -import { ImageField } from '../../../new_fields/URLField'; -import { List } from '../../../new_fields/List'; -import { InkingControl } from '../InkingControl'; -import { Doc, WidthSym, HeightSym } from '../../../new_fields/Doc'; -import { faImage } from '@fortawesome/free-solid-svg-icons'; -import { library } from '@fortawesome/fontawesome-svg-core'; -import { ContextMenuItemProps, ContextMenuProps } from '../ContextMenuItem'; var path = require('path'); diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 35ecf12f6..1239b498f 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,19 +1,17 @@ import React = require("react"); +import { action, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; -import { FieldView, FieldViewProps } from './FieldView'; import * as rp from "request-promise"; -import "./VideoBox.scss"; -import { action, IReactionDisposer, reaction, observable } from "mobx"; -import { DocComponent } from "../DocComponent"; -import { positionSchema } from "./DocumentView"; import { makeInterface } from "../../../new_fields/Schema"; -import { pageSchema } from "./ImageBox"; -import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; +import { Cast, FieldValue } from "../../../new_fields/Types"; import { VideoField } from "../../../new_fields/URLField"; -import "./VideoBox.scss"; import { RouteStore } from "../../../server/RouteStore"; import { DocServer } from "../../DocServer"; -import { actionFieldDecorator } from "mobx/lib/internal"; +import { DocComponent } from "../DocComponent"; +import { positionSchema } from "./DocumentView"; +import { FieldView, FieldViewProps } from './FieldView'; +import { pageSchema } from "./ImageBox"; +import "./VideoBox.scss"; type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; const VideoDocument = makeInterface(positionSchema, pageSchema); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 2239a8e38..98c57fc75 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,12 +1,11 @@ -import "./WebBox.scss"; -import React = require("react"); -import { FieldViewProps, FieldView } from './FieldView'; +import { observer } from "mobx-react"; import { HtmlField } from "../../../new_fields/HtmlField"; import { WebField } from "../../../new_fields/URLField"; -import { observer } from "mobx-react"; -import { computed, reaction, IReactionDisposer } from 'mobx'; import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; +import { FieldView, FieldViewProps } from './FieldView'; +import "./WebBox.scss"; +import React = require("react"); @observer export class WebBox extends React.Component { -- cgit v1.2.3-70-g09d2 From 6cd80efe5a467ce3f4eef31db589f6ccddd84f49 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 5 Jun 2019 09:26:10 -0400 Subject: follow text links on pointer up. prevent web page changing when dropping URL onto Dash. --- src/client/views/MainView.tsx | 8 +++++++- src/client/views/nodes/FormattedTextBox.tsx | 28 ++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index a093ffdec..42d5929bf 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -170,6 +170,12 @@ export class MainView extends React.Component { } } + onDrop = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + console.log("Drop"); + } + @action onResize = (r: any) => { this.pwidth = r.offset.width; @@ -203,7 +209,7 @@ export class MainView extends React.Component { const pres = mainCont ? FieldValue(Cast(mainCont.presentationView, Doc)) : undefined; return {({ measureRef }) => -
+
{content} {pres ? : null}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 5c635cc0c..9affa0730 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -21,8 +21,6 @@ import { SelectionManager } from "../../util/SelectionManager"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; import { undoBatch, UndoManager } from "../../util/UndoManager"; -import { ContextMenu } from "../../views/ContextMenu"; -import { CollectionDockingView } from "../collections/CollectionDockingView"; import { DocComponent } from "../DocComponent"; import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from "./FieldView"; @@ -223,6 +221,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } + _linkClicked = ""; onPointerDown = (e: React.PointerEvent): void => { if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); @@ -230,23 +229,17 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._toolTipTextMenu.tooltip.style.opacity = "0"; } } - let ctrlKey = e.ctrlKey; + this._linkClicked = ""; if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) { let href = (e.target as any).href; for (let parent = (e.target as any).parentNode; !href && parent; parent = parent.parentNode) { href = parent.childNodes[0].href; } - if (href) { - if (href.indexOf(DocServer.prepend("/doc/")) === 0) { - let docid = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; - DocServer.GetRefField(docid).then(f => { - (f instanceof Doc) && DocumentManager.Instance.jumpToDocument(f, ctrlKey, document => this.props.addDocTab(document, "inTab")) - }); - } + if (href && href.indexOf(DocServer.prepend("/doc/")) === 0) { + this._linkClicked = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; e.stopPropagation(); e.preventDefault(); } - } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { this._gotDown = true; @@ -257,6 +250,14 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) { this._toolTipTextMenu.tooltip.style.opacity = "1"; } + let ctrlKey = e.ctrlKey; + if (this._linkClicked) { + DocServer.GetRefField(this._linkClicked).then(f => { + (f instanceof Doc) && DocumentManager.Instance.jumpToDocument(f, ctrlKey, document => this.props.addDocTab(document, "inTab")); + }); + e.stopPropagation(); + e.preventDefault(); + } if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } @@ -280,6 +281,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onClick = (e: React.MouseEvent): void => { this._proseRef.current!.focus(); + if (this._linkClicked) { + e.preventDefault(); + e.stopPropagation(); + } } onMouseDown = (e: React.MouseEvent): void => { if (!this.props.isSelected()) { // preventing default allows the onClick to be generated instead of being swallowed by the text box itself @@ -363,7 +368,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onPointerUp={this.onPointerUp} onPointerDown={this.onPointerDown} onMouseDown={this.onMouseDown} - onContextMenu={this.specificContextMenu} // tfs: do we need this event handler onWheel={this.onPointerWheel} onPointerEnter={this.onPointerEnter} -- cgit v1.2.3-70-g09d2 From e24bf03dd4edab2e5be2d73a6dc7f9c01fc5da85 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 5 Jun 2019 13:04:58 -0400 Subject: cleaned up handling of dropped urls and prosemirror clippings. --- src/client/views/collections/CollectionSubView.tsx | 23 ++++++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 20 +-------- src/client/views/nodes/FormattedTextBox.tsx | 47 +++++++++++++++++----- 3 files changed, 56 insertions(+), 34 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 31e662da5..06d77fec5 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -17,6 +17,7 @@ import { CollectionPDFView } from "./CollectionPDFView"; import { CollectionVideoView } from "./CollectionVideoView"; import { CollectionView } from "./CollectionView"; import React = require("react"); +import { FormattedTextBox } from "../nodes/FormattedTextBox"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; @@ -166,11 +167,23 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { e.stopPropagation(); e.preventDefault(); - if (html && html.indexOf(document.location.origin)) { // prosemirror text containing link to dash document - let start = html.indexOf(window.location.origin); - let path = html.substr(start, html.length - start); - let docid = path.substr(0, path.indexOf("\">")).replace(DocServer.prepend("/doc/"), "").split("?")[0]; - DocServer.GetRefField(docid).then(f => (f instanceof Doc) && this.props.addDocument(f, false)); + if (html && FormattedTextBox.IsFragment(html)) { + let href = FormattedTextBox.GetHref(html); + if (href) { + let docid = FormattedTextBox.GetDocFromUrl(href); + if (docid) { // prosemirror text containing link to dash document + DocServer.GetRefField(docid).then(f => { + if (f instanceof Doc) { + if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView + (f instanceof Doc) && this.props.addDocument(f, false); + } + }); + } else { + this.props.addDocument && this.props.addDocument(Docs.WebDocument(href, options)); + } + } else if (text) { + this.props.addDocument && this.props.addDocument(Docs.TextDocument({ ...options, documentText: "@@@" + text }), false); + } return; } if (html && html.indexOf(" { var pt = this.getTransform().transformPoint(e.pageX, e.pageY); - let html = e.dataTransfer.getData("text/html"); - if (html && html.indexOf(document.location.origin)) { // prosemirror text containing link to dash document - e.stopPropagation(); - e.preventDefault(); - let start = html.indexOf(window.location.origin); - let path = html.substr(start, html.length - start); - let docid = path.substr(0, path.indexOf("\">")).replace(DocServer.prepend("/doc/"), "").split("?")[0]; - DocServer.GetRefField(docid).then(f => { - if (f instanceof Doc) { - f.x = pt[0]; - f.y = pt[1]; - (f instanceof Doc) && this.props.addDocument(f, false); - } - }); - return; - } else { - super.onDrop(e, { x: pt[0], y: pt[1] }); - } + super.onDrop(e, { x: pt[0], y: pt[1] }); } onDragOver = (): void => { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 9eef38e0a..478e7ce93 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -12,7 +12,7 @@ import { RichTextField } from "../../../new_fields/RichTextField"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { DocServer } from "../../DocServer"; -import { DocUtils } from '../../documents/Documents'; +import { DocUtils, Docs } from '../../documents/Documents'; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; import buildKeymap from "../../util/ProsemirrorKeymap"; @@ -27,6 +27,7 @@ import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); +import { Id } from '../../../new_fields/FieldSymbols'; library.add(faEdit); library.add(faSmile); @@ -68,15 +69,40 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe private _ref: React.RefObject; private _proseRef: React.RefObject; private _editorView: Opt; - private _gotDown: boolean = false; + private _toolTipTextMenu: TooltipTextMenu | undefined = undefined; + private _lastState: any = undefined; + private _applyingChange: boolean = false; private _dropDisposer?: DragManager.DragDropDisposer; + private _linkClicked = ""; private _reactionDisposer: Opt; private _inputReactionDisposer: Opt; private _proxyReactionDisposer: Opt; public get CurrentDiv(): HTMLDivElement { return this._ref.current!; } + @observable _entered = false; @observable public static InputBoxOverlay?: FormattedTextBox = undefined; public static InputBoxOverlayScroll: number = 0; + public static IsFragment(html: string) { + return html.indexOf("data-pm-slice") !== -1; + } + public static GetHref(html: string): string { + let parser = new DOMParser(); + let parsedHtml = parser.parseFromString(html, 'text/html'); + if (parsedHtml.body.childNodes.length === 1 && parsedHtml.body.childNodes[0].childNodes.length === 1 && + (parsedHtml.body.childNodes[0].childNodes[0] as any).href) { + return (parsedHtml.body.childNodes[0].childNodes[0] as any).href; + } + return ""; + } + public static GetDocFromUrl(url: string) { + if (url.startsWith(document.location.origin)) { + let start = url.indexOf(window.location.origin); + let path = url.substr(start, url.length - start); + let docid = path.replace(DocServer.prepend("/doc/"), "").split("?")[0]; + return docid; + } + return ""; + } constructor(props: FieldViewProps) { super(props); @@ -88,9 +114,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - _applyingChange: boolean = false; - _lastState: any = undefined; dispatchTransaction = (tx: Transaction) => { if (this._editorView) { const state = this._lastState = this._editorView.state.apply(tx); @@ -221,7 +245,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - _linkClicked = ""; onPointerDown = (e: React.PointerEvent): void => { if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); @@ -235,14 +258,19 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe for (let parent = (e.target as any).parentNode; !href && parent; parent = parent.parentNode) { href = parent.childNodes[0].href; } - if (href && href.indexOf(DocServer.prepend("/doc/")) === 0) { - this._linkClicked = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; + if (href) { + if (href.indexOf(DocServer.prepend("/doc/")) === 0) { + this._linkClicked = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; + } else { + let webDoc = Docs.WebDocument(href, { x: NumCast(this.props.Document.x, 0) + NumCast(this.props.Document.width, 0), y: NumCast(this.props.Document.y) }); + this.props.addDocument && this.props.addDocument(webDoc); + this._linkClicked = webDoc[Id]; + } e.stopPropagation(); e.preventDefault(); } } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { - this._gotDown = true; e.preventDefault(); } } @@ -302,7 +330,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe }); } - _toolTipTextMenu: TooltipTextMenu | undefined = undefined; tooltipLinkingMenuPlugin() { let myprops = this.props; return new Plugin({ @@ -338,8 +365,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - @observable - _entered = false; @action onPointerEnter = (e: React.PointerEvent) => { this._entered = true; -- cgit v1.2.3-70-g09d2 From 1087133d71ef2ac7df6976c61685167ed0fe71d9 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 5 Jun 2019 14:09:40 -0400 Subject: cleaned up selections somewhat so that PDFs don't flicker when manipulating annotations. --- src/client/util/SelectionManager.ts | 24 +++++++++------------- src/client/views/DocumentDecorations.tsx | 1 - .../views/collections/CollectionBaseView.tsx | 2 +- src/client/views/collections/CollectionPDFView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 - .../collections/collectionFreeForm/MarqueeView.tsx | 1 - src/client/views/nodes/PDFBox.tsx | 16 +++++++-------- 7 files changed, 20 insertions(+), 27 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 8c92c2023..5311841e1 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -21,6 +21,13 @@ export namespace SelectionManager { doc.props.whenActiveChanged(true); } } + @action + DeSelectDoc(doc: DocumentView): void { + if (manager.SelectedDocuments.indexOf(doc) !== -1) { + manager.SelectedDocuments.splice(manager.SelectedDocuments.indexOf(doc), 1); + doc.props.whenActiveChanged(false); + } + } @action DeselectAll(): void { @@ -28,16 +35,6 @@ export namespace SelectionManager { manager.SelectedDocuments = []; FormattedTextBox.InputBoxOverlay = undefined; } - @action - ReselectAll() { - let sdocs = manager.SelectedDocuments.map(d => d); - manager.SelectedDocuments = []; - return sdocs; - } - @action - ReselectAll2(sdocs: DocumentView[]) { - sdocs.map(s => SelectionManager.SelectDoc(s, true)); - } } const manager = new Manager(); @@ -49,6 +46,9 @@ export namespace SelectionManager { export function IsSelected(doc: DocumentView): boolean { return manager.SelectedDocuments.indexOf(doc) !== -1; } + export function DeSelectDoc(doc: DocumentView): void { + manager.DeSelectDoc(doc); + } export function DeselectAll(except?: Doc): void { let found: DocumentView | undefined = undefined; @@ -62,10 +62,6 @@ export namespace SelectionManager { if (found) manager.SelectDoc(found, false); } - export function ReselectAll() { - let sdocs = manager.ReselectAll(); - setTimeout(() => manager.ReselectAll2(sdocs), 0); - } export function SelectedDocuments(): Array { return manager.SelectedDocuments; } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 37895516a..cdd537760 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -463,7 +463,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> e.stopPropagation(); this._resizing = ""; this.Interacting = false; - SelectionManager.ReselectAll(); if (e.button === 0) { e.preventDefault(); this._isPointerDown = false; diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 9350dc974..cb92464e5 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -158,7 +158,7 @@ export class CollectionBaseView extends React.Component { @action.bound moveDocument(doc: Doc, targetCollection: Doc, addDocument: (doc: Doc) => boolean): boolean { - if (this.props.Document === targetCollection) { + if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { return true; } if (this.removeDocument(doc)) { diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 5e51437a4..25c1535b3 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -70,7 +70,7 @@ export class CollectionPDFView extends React.Component { return ( <> - {this.props.isSelected() ? this.uIButtons : (null)} + {this.props.active() ? this.uIButtons : (null)} ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 634b4dfa0..582f93c2e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -104,7 +104,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } this.bringToFront(d); }); - SelectionManager.ReselectAll(); } return true; } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 9ec941eff..81ca4c29a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -325,7 +325,6 @@ export class MarqueeView extends React.Component } else { this.props.addDocument(newCollection, false); - SelectionManager.DeselectAll(); this.props.selectDocuments([newCollection]); } this.cleanupInteractions(false); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index aa29a7170..855c744e6 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -68,20 +68,21 @@ export class PDFBox extends DocComponent(PdfDocumen @observable private _currAnno: any = []; @observable private _interactive: boolean = false; - @observable private _loaded: boolean = false; @computed private get curPage() { return NumCast(this.Document.curPage, 1); } @computed private get thumbnailPage() { return NumCast(this.props.Document.thumbnailPage, -1); } componentDidMount() { - let wasSelected = this.props.isSelected(); + let wasSelected = this.props.active(); this._reactionDisposer = reaction( - () => [this.props.isSelected(), this.curPage], + () => [this.props.active(), this.curPage], () => { - if (this.curPage > 0 && !this.props.isTopMost && this.curPage !== this.thumbnailPage && wasSelected && !this.props.isSelected()) { - this.saveThumbnail(); - } - wasSelected = this._interactive = this.props.isSelected(); + setTimeout(action(() => { // this forces the active() check to happen after all changes in a transaction have occurred. + if (this.curPage > 0 && !this.props.isTopMost && this.curPage !== this.thumbnailPage && wasSelected && !this.props.active()) { + this.saveThumbnail(); + } + wasSelected = this._interactive = this.props.active(); + }), 0); }, { fireImmediately: true }); @@ -276,7 +277,6 @@ export class PDFBox extends DocComponent(PdfDocumen if (this._perPageInfo.length === 0) { //Makes sure it only runs once this._perPageInfo = [...Array(page._transport.numPages)]; } - this._loaded = true; } @action -- cgit v1.2.3-70-g09d2 From 852bd5c7b7e8d6c01ff0e6dbb5cef35f4bfd9617 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 6 Jun 2019 22:49:25 -0400 Subject: added unfreeze for images, pdfs, etc. allows margins. improved rotate for images. added ctrl-drag to resize text. fixed minimizing to work with scaled views --- src/client/views/DocumentDecorations.tsx | 20 +++++++++++++--- .../views/collections/CollectionStackingView.tsx | 13 +++++++++- src/client/views/nodes/DocumentView.tsx | 28 +++++++--------------- src/client/views/nodes/ImageBox.tsx | 14 +++++++---- 4 files changed, 47 insertions(+), 28 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ee76f718d..f22fecb98 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -6,7 +6,7 @@ import { observer } from "mobx-react"; import { Doc } from "../../new_fields/Doc"; import { List } from "../../new_fields/List"; import { listSpec } from "../../new_fields/Schema"; -import { Cast, NumCast, StrCast } from "../../new_fields/Types"; +import { Cast, NumCast, StrCast, BoolCast } from "../../new_fields/Types"; import { emptyFunction, Utils } from "../../Utils"; import { Docs } from "../documents/Documents"; import { DocumentManager } from "../util/DocumentManager"; @@ -443,16 +443,30 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let actualdH = Math.max(height + (dH * scale), 20); doc.x = (doc.x || 0) + dX * (actualdW - width); doc.y = (doc.y || 0) + dY * (actualdH - height); + let proto = Doc.GetProto(doc); + let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect, false) && nwidth && nheight); + if (fixedAspect && (!nwidth || !nheight)) { + proto.nativeWidth = doc.width; + proto.nativeHeight = doc.height; + proto.ignoreAspect = true; + } if (nwidth > 0 && nheight > 0) { if (Math.abs(dW) > Math.abs(dH)) { + if (!fixedAspect) proto.nativeWidth = zoomBasis * actualdW / (doc.width || 1) * NumCast(proto.nativeWidth); doc.width = zoomBasis * actualdW; // doc.zoomBasis = zoomBasis * width / actualdW; + if (fixedAspect) doc.height = nheight / nwidth * doc.width; + else doc.height = zoomBasis * actualdH; + proto.nativeHeight = (doc.height || 0) / doc.width * NumCast(proto.nativeWidth); } else { - doc.width = nwidth / nheight * zoomBasis * actualdH; + if (!fixedAspect) proto.nativeHeight = zoomBasis * actualdH / (doc.height || 1) * NumCast(proto.nativeHeight); + doc.height = zoomBasis * actualdH; //doc.zoomBasis = zoomBasis * height / actualdH; + if (fixedAspect) doc.width = nwidth / nheight * doc.height; + else doc.width = zoomBasis * actualdW; + proto.nativeWidth = (doc.width || 0) / doc.height * NumCast(proto.nativeHeight); } - doc.height = nheight / nwidth * doc.width; } else { doc.width = zoomBasis * actualdW; if (docHeightBefore === doc.height) doc.height = zoomBasis * actualdH; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index af7e02e06..eeae498a6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -11,6 +11,7 @@ import { DocumentView } from "../nodes/DocumentView"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; +import { ContextMenu } from "../ContextMenu"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { @@ -147,12 +148,22 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
); }) } + onContextMenu = (e: React.MouseEvent): void => { + if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + ContextMenu.Instance.addItem({ + description: "Toggle multi-column", + event: () => this.props.Document.singleColumn = !BoolCast(this.props.Document.singleColumn, false), icon: "file-pdf" + }); + } + } render() { - let cols = this.singleColumn ? 1 : Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + 2 * this.gridGap)); + let cols = this.singleColumn ? 1 : Math.min(this.childDocs.filter(d => !d.isMinimized).length, + Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + 2 * this.gridGap))); let templatecols = ""; for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; return (
e.stopPropagation()}>
(Docu toggleMinimized = async () => { let minimizedDoc = await Cast(this.props.Document.minimizedDoc, Doc); if (minimizedDoc) { - let scrpt = this.props.ScreenToLocalTransform().inverse().transformPoint( + let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint( NumCast(minimizedDoc.x) - NumCast(this.Document.x), NumCast(minimizedDoc.y) - NumCast(this.Document.y)); this.props.collapseToPoint && this.props.collapseToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs)); } @@ -246,7 +246,7 @@ export class DocumentView extends DocComponent(Docu this.props.addDocTab(getDispDoc(maxDoc), maxLocation))); } } else { - let scrpt = this.props.ScreenToLocalTransform().inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2); + let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2); this.props.collapseToPoint && this.props.collapseToPoint(scrpt, expandedProtoDocs); } } @@ -374,23 +374,13 @@ export class DocumentView extends DocComponent(Docu } freezeNativeDimensions = (e: React.MouseEvent): void => { - if (NumCast(this.props.Document.nativeWidth)) { - let proto = Doc.GetProto(this.props.Document); - let nw = proto.nativeWidth; - let nh = proto.nativeHeight; - proto.nativeWidth = proto.nativeHeight = undefined; - this.props.Document.width = this.props.Document.frozenWidth; - this.props.Document.height = this.props.Document.frozenHeight; - } - else { - let scale = this.props.ScreenToLocalTransform().Scale * NumCast(this.props.Document.zoomBasis, 1); - let scr = this.screenRect(); - let proto = Doc.GetProto(this.props.Document); - this.props.Document.frozenWidth = this.props.Document.width; - this.props.Document.frozenHeight = this.props.Document.height; - this.props.Document.height = proto.nativeHeight = scr.height * scale; - this.props.Document.width = proto.nativeWidth = scr.width * scale; + let proto = Doc.GetProto(this.props.Document); + if (proto.ignoreAspect === undefined && !proto.nativeWidth) { + proto.nativeWidth = this.props.PanelWidth(); + proto.nativeHeight = this.props.PanelHeight(); + proto.ignoreAspect = true; } + proto.ignoreAspect = !BoolCast(proto.ignoreAspect, false); } @action @@ -412,7 +402,7 @@ export class DocumentView extends DocComponent(Docu subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Open...", subitems: subitems }); - cm.addItem({ description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", event: this.freezeNativeDimensions, icon: "edit" }); + cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "edit" }); cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); cm.addItem({ diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 06ecc794b..0d19508fa 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -136,12 +136,15 @@ export class ImageBox extends DocComponent(ImageD subitems.push({ description: "Copy path", event: () => Utils.CopyText(url), icon: "expand-arrows-alt" }); subitems.push({ description: "Rotate", event: action(() => { - this.props.Document.rotation = (NumCast(this.props.Document.rotation) + 90) % 360; + let proto = Doc.GetProto(this.props.Document); let nw = this.props.Document.nativeWidth; - this.props.Document.nativeWidth = this.props.Document.nativeHeight; - this.props.Document.nativeHeight = nw; + let nh = this.props.Document.nativeHeight; let w = this.props.Document.width; - this.props.Document.width = this.props.Document.height; + let h = this.props.Document.height; + proto.rotation = (NumCast(this.props.Document.rotation) + 90) % 360; + proto.nativeWidth = nh; + proto.nativeHeight = nw; + this.props.Document.width = h; this.props.Document.height = w; }), icon: "expand-arrows-alt" }); @@ -198,6 +201,7 @@ export class ImageBox extends DocComponent(ImageD let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx let nativeWidth = FieldValue(this.Document.nativeWidth, pw); + let nativeHeight = FieldValue(this.Document.nativeHeight, 0); let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"]; // this._curSuffix = ""; // if (w > 20) { @@ -211,7 +215,7 @@ export class ImageBox extends DocComponent(ImageD let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; let rotation = NumCast(this.props.Document.rotation, 0); let aspect = (rotation % 180) ? this.props.Document[HeightSym]() / this.props.Document[WidthSym]() : 1; - let shift = (rotation % 180) ? (this.props.Document[HeightSym]() - this.props.Document[WidthSym]() / aspect) / 2 : 0; + let shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0; return (
Date: Fri, 7 Jun 2019 10:21:55 -0400 Subject: fixed some pinterest layout issues. --- .../views/collections/CollectionBaseView.scss | 11 ++++++++ .../views/collections/CollectionBaseView.tsx | 4 +-- .../views/collections/CollectionStackingView.scss | 20 ++++--------- .../views/collections/CollectionStackingView.tsx | 33 +++++++++++----------- src/client/views/nodes/DocumentView.tsx | 3 +- 5 files changed, 36 insertions(+), 35 deletions(-) create mode 100644 src/client/views/collections/CollectionBaseView.scss (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionBaseView.scss b/src/client/views/collections/CollectionBaseView.scss new file mode 100644 index 000000000..1f5acb96a --- /dev/null +++ b/src/client/views/collections/CollectionBaseView.scss @@ -0,0 +1,11 @@ +@import "../globalCssVariables"; +#collectionBaseView { + border-width: 0; + box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw; + border-color: $light-color-secondary; + border-style: solid; + border-radius: 0 0 $border-radius $border-radius; + box-sizing: border-box; + border-radius: inherit; + pointer-events: all; +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index cb92464e5..ddec587a9 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -9,6 +9,7 @@ import { Cast, FieldValue, NumCast, PromiseValue } from '../../../new_fields/Typ import { SelectionManager } from '../../util/SelectionManager'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; +import './CollectionBaseView.scss'; export enum CollectionViewType { Invalid, @@ -178,8 +179,7 @@ export class CollectionBaseView extends React.Component { }; const viewtype = this.collectionViewType; return ( -
{viewtype !== undefined ? this.props.children(viewtype, props) : (null)}
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 4d84aaaa9..af194aec9 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -1,19 +1,6 @@ @import "../globalCssVariables"; - .collectionStackingView { - top: 0; - left: 0; - display: flex; - flex-direction: column; - width: 100%; - position: absolute; overflow-y: auto; - border-width: 0; - box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw; - border-color: $light-color-secondary; - border-style: solid; - border-radius: 0 0 $border-radius $border-radius; - box-sizing: border-box; .collectionStackingView-docView-container { width: 45%; @@ -33,9 +20,12 @@ width:100%; height:100%; position: absolute; - } - .collectionStackingView-masonryGrid { display:grid; + top: 0; + left: 0; + width: 100%; + position: absolute; + } .collectionStackingView-description { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index eeae498a6..b8eb4ac84 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -32,11 +32,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return (nw && nh) ? wid * aspect : d[HeightSym](); } componentDidMount() { - this._heightDisposer = reaction(() => [this.yMargin, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], + this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], () => { if (this.singleColumn) { - this.props.Document.height = this.childDocs.filter(d => !d.isMinimized).reduce((height, d) => - height + this.singleColDocHeight(d) + this.yMargin + let children = this.childDocs.filter(d => !d.isMinimized); + this.props.Document.height = children.reduce((height, d, i) => + height + this.singleColDocHeight(d) + (i === children.length - 1 ? this.yMargin : this.gridGap) , this.yMargin); } }, { fireImmediately: true }); @@ -78,7 +79,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get singleColumnChildren() { - return this.childDocs.filter(d => !d.isMinimized).map((d, i) => { + let children = this.childDocs.filter(d => !d.isMinimized); + return children.map((d, i) => { let dref = React.createRef(); let script = undefined; let colWidth = () => d.nativeWidth ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth; @@ -87,7 +89,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return
+ style={{ width: colWidth(), height: rowHeight(), marginLeft: "auto", marginRight: "auto" }} > doc) { } @computed get children() { + trace(); return this.childDocs.filter(d => !d.isMinimized).map((d, i) => { let dref = React.createRef(); let dxf = () => this.getDocTransform(d, dref.current!); - let colSpan = 1;//Math.ceil((this.columnWidth + this.gridGap) / (this._gridSize + this.gridGap)); let rowSpan = Math.ceil((this.columnWidth / d[WidthSym]() * d[HeightSym]() + this.gridGap) / (this._gridSize + this.gridGap)); let childFocus = (doc: Doc) => { doc.libraryBrush = true; @@ -124,7 +126,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { height: NumCast(d.nativeHeight, d[HeightSym]()), transformOrigin: "top left", gridRowEnd: `span ${rowSpan}`, - gridColumnEnd: `span ${colSpan}`, + gridColumnEnd: `span 1`, transform: `scale(${this.columnWidth / NumCast(d.nativeWidth, d[WidthSym]())}, ${this.columnWidth / NumCast(d.nativeWidth, d[WidthSym]())})` }} > doc) { } } render() { - let cols = this.singleColumn ? 1 : Math.min(this.childDocs.filter(d => !d.isMinimized).length, - Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + 2 * this.gridGap))); + let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.childDocs.filter(d => !d.isMinimized).length, + Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); let templatecols = ""; for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; return ( -
e.stopPropagation()}> +
e.stopPropagation()} style={{ - padding: `${this.yMargin}px ${this.xMargin}px 0px ${this.xMargin}px`, + padding: this.singleColumn ? `${this.yMargin}px ${this.xMargin}px ${this.yMargin}px ${this.xMargin}px` : `${this.yMargin}px ${this.xMargin}px`, margin: "auto", - width: this.singleColumn ? undefined : `${cols * (this.columnWidth + this.gridGap)}px`, + width: this.singleColumn ? undefined : `${cols * (this.columnWidth + this.gridGap) + 2 * this.xMargin - this.gridGap}px`, height: "100%", position: "relative", gridGap: this.gridGap, @@ -178,8 +180,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }} > {this.singleColumn ? this.singleColumnChildren : this.children} -
-
+
); } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 36a5358f0..ff2b9842f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,6 +1,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faAlignCenter, faCaretSquareRight, faCompressArrowsAlt, faExpandArrowsAlt, faLayerGroup, faSquare, faTrash, faConciergeBell, faFolder, faMapPin, faLink, faFingerprint, faCrosshairs, faDesktop } from '@fortawesome/free-solid-svg-icons'; -import { action, computed, IReactionDisposer, reaction } from "mobx"; +import { action, computed, IReactionDisposer, reaction, trace } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; @@ -439,7 +439,6 @@ export class DocumentView extends DocComponent(Docu var scaling = this.props.ContentScaling(); var nativeHeight = this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; var nativeWidth = this.nativeWidth > 0 ? `${this.nativeWidth}px` : "100%"; - return (
Date: Sat, 8 Jun 2019 09:18:46 -0400 Subject: fixed deletion of keys to actually remove them on the server. added '=' syntax on kvp to set on proto. := sets a computed script. =:= sets computed script on proto --- src/client/views/nodes/KeyValueBox.tsx | 49 ++++++++++++++++++++------------- src/client/views/nodes/KeyValuePair.tsx | 20 ++++---------- src/new_fields/util.ts | 3 +- 3 files changed, 37 insertions(+), 35 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 849f17aa4..917be734d 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -2,13 +2,14 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app -import { CompileScript } from "../../util/Scripting"; +import { CompileScript, ScriptOptions } from "../../util/Scripting"; import { FieldView, FieldViewProps } from './FieldView'; import "./KeyValueBox.scss"; import { KeyValuePair } from "./KeyValuePair"; import React = require("react"); import { NumCast, Cast, FieldValue } from "../../../new_fields/Types"; import { Doc, Field } from "../../../new_fields/Doc"; +import { ComputedField } from "../../../fields/ScriptField"; @observer export class KeyValueBox extends React.Component { @@ -27,28 +28,38 @@ export class KeyValueBox extends React.Component { @action onEnterKey = (e: React.KeyboardEvent): void => { if (e.key === 'Enter') { - if (this._keyInput && this._valueInput) { - let doc = this.fieldDocToLayout; - if (!doc) { - return; + if (this._keyInput && this._valueInput && this.fieldDocToLayout) { + if (KeyValueBox.SetField(this.fieldDocToLayout, this._keyInput, this._valueInput)) { + this._keyInput = ""; + this._valueInput = ""; } - let realDoc = doc; - - let script = CompileScript(this._valueInput, { addReturn: true }); - if (!script.compiled) { - return; - } - let res = script.run(); - if (!res.success) return; - const field = res.result; - if (Field.IsField(field)) { - realDoc[this._keyInput] = field; - } - this._keyInput = ""; - this._valueInput = ""; } } } + public static SetField(doc: Doc, key: string, value: string) { + let eq = value.startsWith("="); + value = eq ? value.substr(1) : value; + let dubEq = value.startsWith(":="); + value = dubEq ? value.substr(2) : value; + let options: ScriptOptions = { addReturn: true }; + if (dubEq) options.typecheck = false; + let script = CompileScript(value, options); + if (!script.compiled) { + return false; + } + let field = new ComputedField(script); + if (!dubEq) { + let res = script.run(); + if (!res.success) return false; + field = res.result; + } + if (Field.IsField(field, true)) { + let target = !eq ? doc : Doc.GetProto(doc); + target[key] = field; + return true; + } + return false; + } onPointerDown = (e: React.PointerEvent): void => { if (e.buttons === 1 && this.props.isSelected()) { diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 228d07018..e8bc17532 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -2,7 +2,7 @@ import { action, observable } from 'mobx'; import { observer } from "mobx-react"; import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app import { emptyFunction, returnFalse, returnZero, returnTrue } from '../../../Utils'; -import { CompileScript } from "../../util/Scripting"; +import { CompileScript, CompiledScript, ScriptOptions } from "../../util/Scripting"; import { Transform } from '../../util/Transform'; import { EditableView } from "../EditableView"; import { FieldView, FieldViewProps } from './FieldView'; @@ -11,6 +11,8 @@ import "./KeyValuePair.scss"; import React = require("react"); import { Doc, Opt, Field } from '../../../new_fields/Doc'; import { FieldValue } from '../../../new_fields/Types'; +import { ComputedField } from '../../../fields/ScriptField'; +import { KeyValueBox } from './KeyValueBox'; // Represents one row in a key value plane @@ -66,20 +68,8 @@ export class KeyValuePair extends React.Component { } return ""; }} - SetValue={(value: string) => { - let script = CompileScript(value, { addReturn: true }); - if (!script.compiled) { - return false; - } - let res = script.run(); - if (!res.success) return false; - const field = res.result; - if (Field.IsField(field, true)) { - props.Document[props.fieldKey] = field; - return true; - } - return false; - }}> + SetValue={(value: string) => + KeyValueBox.SetField(props.Document, props.fieldKey, value)}> ); diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index ad07d05a3..fe0da2e7a 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -44,7 +44,8 @@ export const setter = action(function (target: any, prop: string | symbol | numb } else { target.__fields[prop] = value; } - target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } }); + if (value === undefined) target[Update]({ '$unset': { ["fields." + prop]: "" } }); + else target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } }); UndoManager.AddEvent({ redo: () => receiver[prop] = value, undo: () => receiver[prop] = curValue -- cgit v1.2.3-70-g09d2 From 2500204978e2dd15c439adfc400388b7bb3caa01 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 8 Jun 2019 20:48:10 -0400 Subject: several fixes to templates and a fix for link dragging. --- src/client/util/DragManager.ts | 1 + src/client/views/MainOverlayTextBox.tsx | 2 +- src/client/views/Templates.tsx | 48 +++++++++++++++++------------ src/client/views/nodes/DocumentView.tsx | 16 ++++++++-- src/client/views/nodes/FormattedTextBox.tsx | 15 ++++++--- 5 files changed, 55 insertions(+), 27 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 32476b785..4c9f798a8 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -269,6 +269,7 @@ export namespace DragManager { let lastX = downX; let lastY = downY; const moveHandler = (e: PointerEvent) => { + e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { dragData.userDropAction = e.ctrlKey || e.altKey ? "alias" : undefined; } diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index d1224febe..6bbd70a25 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -96,7 +96,7 @@ export class MainOverlayTextBox extends React.Component return
-
diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 0cd367bcb..8943bbcaf 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -47,42 +47,52 @@ export namespace Templates {
` ); - export const TitleOverlay = new Template("TitleOverlay", TemplatePosition.InnerTop, - `
+ export const ImageTitle = new Template("Image Title", TemplatePosition.InnerTop, + `
{layout}
{props.Document.title}
` ); - export const Title = new Template("Title", TemplatePosition.InnerTop, - `
-
{layout}
-
+ export const TextTitle = new Template("Text Title", TemplatePosition.InnerTop, + `
+
{props.Document.title}
+
+
{layout}
+
` ); - export const Bullet = new Template("Bullet", TemplatePosition.InnerTop, - `
-
{layout}
-
- + export const Header = new Template("Header", TemplatePosition.InnerTop, + `< div style = "display:flex; flex-direction:column; height:100%;" > +
+
-
` +
{layout}
+
` ); + + export const Bullet = new Template("Bullet", TemplatePosition.InnerTop, + `< div > +
{layout}
+
+ +
+
` ); export function ImageOverlay(width: number, height: number, field: string = "thumbnail") { - return (`
-
{layout}
-
- + return (`< div > +
{layout}
+
+
-
`); +
`); } - export const TemplateList: Template[] = [Title, TitleOverlay, Caption, Bullet]; + export const TemplateList: Template[] = [TextTitle, Header, ImageTitle, Caption, Bullet]; export function sortTemplates(a: Template, b: Template) { if (a.Position < b.Position) { return -1; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ff2b9842f..85b8a5596 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,6 +1,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faAlignCenter, faCaretSquareRight, faCompressArrowsAlt, faExpandArrowsAlt, faLayerGroup, faSquare, faTrash, faConciergeBell, faFolder, faMapPin, faLink, faFingerprint, faCrosshairs, faDesktop } from '@fortawesome/free-solid-svg-icons'; -import { action, computed, IReactionDisposer, reaction, trace } from "mobx"; +import { action, computed, IReactionDisposer, reaction, trace, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; @@ -123,6 +123,12 @@ export class DocumentView extends DocComponent(Docu set templates(templates: List) { this.props.Document.templates = templates; } screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect(); + constructor(props: DocumentViewProps) { + super(props); + this.selectOnLoad = props.selectOnLoad; + } + + _reactionDisposer?: IReactionDisposer; @action componentDidMount() { @@ -429,11 +435,15 @@ export class DocumentView extends DocComponent(Docu onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; }; isSelected = () => SelectionManager.IsSelected(this); - select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed); + @action select = (ctrlPressed: boolean) => { this.selectOnLoad = false; SelectionManager.SelectDoc(this, ctrlPressed); } + @observable selectOnLoad: boolean = false; @computed get nativeWidth() { return this.Document.nativeWidth || 0; } @computed get nativeHeight() { return this.Document.nativeHeight || 0; } - @computed get contents() { return (); } + @computed get contents() { + return ( + ); + } render() { var scaling = this.props.ContentScaling(); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 478e7ce93..559a9fbfc 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -52,6 +52,8 @@ library.add(faSmile); export interface FormattedTextBoxProps { isOverlay?: boolean; hideOnLeave?: boolean; + height?: string; + color?: string; } const richTextSchema = createSchema({ @@ -206,6 +208,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe private setupEditor(config: any, doc?: Doc) { let field = doc ? Cast(doc[this.props.fieldKey], RichTextField) : undefined; + let startup = StrCast(this.props.Document.documentText); + startup = startup.startsWith("@@@") ? startup.replace("@@@", "") : ""; + if (!startup && !field && doc) { + startup = StrCast(doc[this.props.fieldKey]); + } if (this._proseRef.current) { this._editorView = new EditorView(this._proseRef.current, { state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), @@ -214,10 +221,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe image(node, view, getPos) { return new ImageResizeView(node, view, getPos); } } }); - let text = StrCast(this.props.Document.documentText); - if (text.startsWith("@@@")) { + if (startup) { this.props.Document.proto!.documentText = undefined; - this._editorView.dispatch(this._editorView.state.tr.insertText(text.replace("@@@", ""))); + this._editorView.dispatch(this._editorView.state.tr.insertText(startup)); } } @@ -380,9 +386,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe return (
Date: Sun, 9 Jun 2019 20:32:06 -0400 Subject: added a link context for link targets. --- src/client/documents/Documents.ts | 30 ++++++++++------------ src/client/util/DocumentManager.ts | 29 ++++++++++++++++----- src/client/views/DocumentDecorations.tsx | 3 +-- .../views/collections/CollectionBaseView.tsx | 6 ++--- .../views/collections/CollectionStackingView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 15 ++++++++--- 6 files changed, 52 insertions(+), 33 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index f0fb0c3ed..2ae127e21 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -69,31 +69,27 @@ export interface DocumentOptions { const delegateKeys = ["x", "y", "width", "height", "panX", "panY"]; export namespace DocUtils { - export function MakeLink(source: Doc, target: Doc) { + export function MakeLink(source: Doc, target: Doc, targetContext?: Doc) { let protoSrc = source.proto ? source.proto : source; let protoTarg = target.proto ? target.proto : target; UndoManager.RunInBatch(() => { let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 }); - //let linkDoc = new Doc; - linkDoc.proto!.title = "-link name-"; - linkDoc.proto!.linkDescription = ""; - linkDoc.proto!.linkTags = "Default"; + let linkDocProto = Doc.GetProto(linkDoc); + linkDocProto.title = source.title + " to " + target.title; + linkDocProto.linkDescription = ""; + linkDocProto.linkTags = "Default"; - linkDoc.proto!.linkedTo = target; - linkDoc.proto!.linkedToPage = target.curPage; - linkDoc.proto!.linkedFrom = source; - linkDoc.proto!.linkedFromPage = source.curPage; + linkDocProto.linkedTo = target; + linkDocProto.linkedFrom = source; + linkDocProto.linkedToPage = target.curPage; + linkDocProto.linkedFromPage = source.curPage; + linkDocProto.linkedToContext = targetContext; let linkedFrom = Cast(protoTarg.linkedFromDocs, listSpec(Doc)); - if (!linkedFrom) { - protoTarg.linkedFromDocs = linkedFrom = new List(); - } - linkedFrom.push(linkDoc); - let linkedTo = Cast(protoSrc.linkedToDocs, listSpec(Doc)); - if (!linkedTo) { - protoSrc.linkedToDocs = linkedTo = new List(); - } + !linkedFrom && (protoTarg.linkedFromDocs = linkedFrom = new List()); + !linkedTo && (protoSrc.linkedToDocs = linkedTo = new List()); + linkedFrom.push(linkDoc); linkedTo.push(linkDoc); return linkDoc; }, "make link"); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 65c4b9e4b..ff0c1560b 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -115,7 +115,7 @@ export class DocumentManager { } @undoBatch - public jumpToDocument = async (docDelegate: Doc, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void, linkPage?: number): Promise => { + public jumpToDocument = async (docDelegate: Doc, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void, linkPage?: number, docContext?: Doc): Promise => { let doc = Doc.GetProto(docDelegate); const contextDoc = await Cast(doc.annotationOn, Doc); if (contextDoc) { @@ -123,6 +123,7 @@ export class DocumentManager { const curPage = NumCast(contextDoc.curPage, page); if (page !== curPage) contextDoc.curPage = page; } + let docView: DocumentView | null; // using forceDockFunc as a flag for splitting linked to doc to the right...can change later if needed if (!forceDockFunc && (docView = DocumentManager.Instance.getDocumentView(doc))) { @@ -131,18 +132,34 @@ export class DocumentManager { docView.props.focus(docView.props.Document); } else { if (!contextDoc) { - const actualDoc = Doc.MakeAlias(docDelegate); - actualDoc.libraryBrush = true; - if (linkPage !== undefined) actualDoc.curPage = linkPage; - (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); + if (docContext) { + let targetContextView: DocumentView | null; + if (!forceDockFunc && docContext && (targetContextView = DocumentManager.Instance.getDocumentView(docContext))) { + docContext.panTransformType = "Ease"; + targetContextView.props.focus(docDelegate); + } else { + (dockFunc || CollectionDockingView.Instance.AddRightSplit)(docContext); + setTimeout(() => { + this.jumpToDocument(docDelegate, forceDockFunc, dockFunc, linkPage); + }, 10); + } + } else { + const actualDoc = Doc.MakeAlias(docDelegate); + actualDoc.libraryBrush = true; + if (linkPage !== undefined) actualDoc.curPage = linkPage; + (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); + } } else { let contextView: DocumentView | null; docDelegate.libraryBrush = true; if (!forceDockFunc && (contextView = DocumentManager.Instance.getDocumentView(contextDoc))) { contextDoc.panTransformType = "Ease"; - contextView.props.focus(contextDoc); + contextView.props.focus(docDelegate); } else { (dockFunc || CollectionDockingView.Instance.AddRightSplit)(contextDoc); + setTimeout(() => { + this.jumpToDocument(docDelegate, forceDockFunc, dockFunc, linkPage); + }, 10); } } } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index f22fecb98..7260b00cf 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -432,7 +432,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (rect.width !== 0 && (dX != 0 || dY != 0 || dW != 0 || dH != 0)) { let doc = PositionDocument(element.props.Document); - let docHeightBefore = doc.height; let nwidth = doc.nativeWidth || 0; let nheight = doc.nativeHeight || 0; let zoomBasis = NumCast(doc.zoomBasis, 1); @@ -469,7 +468,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } } else { doc.width = zoomBasis * actualdW; - if (docHeightBefore === doc.height) doc.height = zoomBasis * actualdH; + doc.height = zoomBasis * actualdH; } } }); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index ddec587a9..d120c3a0c 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -101,9 +101,9 @@ export class CollectionBaseView extends React.Component { addDocument(doc: Doc, allowDuplicates: boolean = false): boolean { let props = this.props; var curPage = NumCast(props.Document.curPage, -1); - Doc.SetOnPrototype(doc, "page", curPage); + Doc.GetProto(doc).page = curPage; if (curPage >= 0) { - Doc.SetOnPrototype(doc, "annotationOn", props.Document); + Doc.GetProto(doc).annotationOn = props.Document; } if (!this.createsCycle(doc, props.Document)) { //TODO This won't create the field if it doesn't already exist @@ -141,7 +141,7 @@ export class CollectionBaseView extends React.Component { break; } } - PromiseValue(Cast(doc.annotationOn, Doc)).then((annotationOn) => { + PromiseValue(Cast(doc.annotationOn, Doc)).then(annotationOn => { if (annotationOn === props.Document) { doc.annotationOn = undefined; } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0a119a3b4..cad7cd50c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -153,7 +153,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "Toggle multi-column", - event: () => this.props.Document.singleColumn = !BoolCast(this.props.Document.singleColumn, false), icon: "file-pdf" + event: () => this.props.Document.singleColumn = !BoolCast(this.props.Document.singleColumn, true), icon: "file-pdf" }); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 85b8a5596..2ac6d12bf 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -6,7 +6,7 @@ import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync } from ".. import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { BoolCast, Cast, FieldValue, StrCast, NumCast } from "../../../new_fields/Types"; +import { BoolCast, Cast, FieldValue, StrCast, NumCast, PromiseValue } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { emptyFunction, Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; @@ -261,12 +261,17 @@ export class DocumentView extends DocComponent(Docu linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : expandedDocs[0], linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : expandedDocs[0]]; + let linkedFwdContextDocs = [ + linkedToDocs.length ? await (linkedToDocs[0].linkedToContext) as Doc : linkedFromDocs.length ? await PromiseValue(linkedFromDocs[0].linkedFromContext) as Doc : undefined, + linkedFromDocs.length ? await (linkedFromDocs[0].linkedFromContext) as Doc : linkedToDocs.length ? await PromiseValue(linkedToDocs[0].linkedToContext) as Doc : undefined]; + let linkedFwdPage = [ linkedToDocs.length ? NumCast(linkedToDocs[0].linkedToPage, undefined) : linkedFromDocs.length ? NumCast(linkedFromDocs[0].linkedFromPage, undefined) : undefined, linkedFromDocs.length ? NumCast(linkedFromDocs[0].linkedFromPage, undefined) : linkedToDocs.length ? NumCast(linkedToDocs[0].linkedToPage, undefined) : undefined]; + if (!linkedFwdDocs.some(l => l instanceof Promise)) { let maxLocation = StrCast(linkedFwdDocs[altKey ? 1 : 0].maximizeLocation, "inTab"); - DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, document => this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey ? 1 : 0]); + DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, document => this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey ? 1 : 0], linkedFwdContextDocs[altKey ? 1 : 0]); } } } @@ -333,6 +338,7 @@ export class DocumentView extends DocComponent(Docu let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.Document; + e.stopPropagation(); if (de.mods === "AltKey") { const protoDest = destDoc.proto; const protoSrc = sourceDoc.proto; @@ -343,10 +349,11 @@ export class DocumentView extends DocComponent(Docu dst.nativeHeight = src.nativeHeight; } else { - DocUtils.MakeLink(sourceDoc, destDoc); + const docs = await SearchUtil.Search(`data_l:"${destDoc[Id]}"`, true); + const views = docs.map(d => DocumentManager.Instance.getDocumentView(d)).filter(d => d).map(d => d as DocumentView); + DocUtils.MakeLink(sourceDoc, destDoc, views.length ? views[0].props.Document : undefined); de.data.droppedDocuments.push(destDoc); } - e.stopPropagation(); } } -- cgit v1.2.3-70-g09d2 From c56851026c4054cde26ea36a9a24db14fac6c49c Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 10 Jun 2019 13:03:47 -0400 Subject: fixes for treeview highlighting, templates, field deletion, overlaytext box positioning --- src/Utils.ts | 2 +- src/client/util/DragManager.ts | 6 ++++-- src/client/util/SelectionManager.ts | 9 +++++--- src/client/views/MainOverlayTextBox.tsx | 8 +++++--- src/client/views/Templates.tsx | 16 ++++----------- .../views/collections/CollectionTreeView.tsx | 24 ++++++++++++++-------- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +-- src/client/views/nodes/DocumentView.tsx | 6 +++--- src/new_fields/util.ts | 4 ++-- 9 files changed, 42 insertions(+), 36 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/Utils.ts b/src/Utils.ts index 611c61135..e8a80bdc3 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -15,7 +15,7 @@ export class Utils { return v5(seed, v5.URL); } - public static GetScreenTransform(ele: HTMLElement): { scale: number, translateX: number, translateY: number } { + public static GetScreenTransform(ele?: HTMLElement): { scale: number, translateX: number, translateY: number } { if (!ele) { return { scale: 1, translateX: 1, translateY: 1 }; } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 4c9f798a8..8ee1ad2af 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,9 +1,10 @@ -import { action, runInAction } from "mobx"; +import { action, runInAction, observable } from "mobx"; import { Doc, DocListCastAsync } from "../../new_fields/Doc"; import { Cast } from "../../new_fields/Types"; import { emptyFunction } from "../../Utils"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import * as globalCssVariables from "../views/globalCssVariables.scss"; +import { SelectionManager } from "./SelectionManager"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag(_reference: React.RefObject, docFunc: () => Doc | Promise, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType, options?: any, dontHideOnDrop?: boolean) { @@ -194,7 +195,7 @@ export namespace DragManager { dragDiv.style.pointerEvents = "none"; DragManager.Root().appendChild(dragDiv); } - + SelectionManager.SetIsDragging(true); let scaleXs: number[] = []; let scaleYs: number[] = []; let xs: number[] = []; @@ -293,6 +294,7 @@ export namespace DragManager { }; let hideDragElements = () => { + SelectionManager.SetIsDragging(false); dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); eles.map(ele => (ele.hidden = false)); }; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 0e22d576c..ddad4b818 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -1,4 +1,4 @@ -import { observable, action } from "mobx"; +import { observable, action, runInAction } from "mobx"; import { Doc } from "../../new_fields/Doc"; import { DocumentView } from "../views/nodes/DocumentView"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; @@ -6,8 +6,8 @@ import { NumCast } from "../../new_fields/Types"; export namespace SelectionManager { class Manager { - @observable - SelectedDocuments: Array = []; + @observable IsDragging: boolean = false; + @observable SelectedDocuments: Array = []; @action SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { @@ -51,6 +51,9 @@ export namespace SelectionManager { if (found) manager.SelectDoc(found, false); } + export function SetIsDragging(dragging: boolean) { runInAction(() => manager.IsDragging = dragging); } + export function GetIsDragging() { return manager.IsDragging; } + export function SelectedDocuments(): Array { return manager.SelectedDocuments; } diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 6bbd70a25..0eb3e9707 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -1,7 +1,7 @@ import { action, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { emptyFunction, returnTrue, returnZero } from '../../Utils'; +import { emptyFunction, returnTrue, returnZero, Utils } from '../../Utils'; import { DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; import "normalize.css"; @@ -29,7 +29,8 @@ export class MainOverlayTextBox extends React.Component MainOverlayTextBox.Instance = this; reaction(() => FormattedTextBox.InputBoxOverlay, (box?: FormattedTextBox) => { - if (box) this.setTextDoc(box.props.fieldKey, box.CurrentDiv, box.props.ScreenToLocalTransform); + let sxf = Utils.GetScreenTransform(box ? box.CurrentDiv : undefined); + if (box) this.setTextDoc(box.props.fieldKey, box.CurrentDiv, () => new Transform(-sxf.translateX, -sxf.translateY, 1 / sxf.scale)); else this.setTextDoc(); }); } @@ -93,9 +94,10 @@ export class MainOverlayTextBox extends React.Component if (FormattedTextBox.InputBoxOverlay && this._textTargetDiv) { let textRect = this._textTargetDiv.getBoundingClientRect(); let s = this._textXf().Scale; + let auto = FormattedTextBox.InputBoxOverlay.props.height; return
+ style={{ width: `${textRect.width * s}px`, height: auto ? "auto" : `${textRect.height * s}px` }}> diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 8943bbcaf..3cd525afa 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -41,21 +41,13 @@ export namespace Templates { export const Caption = new Template("Caption", TemplatePosition.OutterBottom, `
-
{layout}
+
{layout}
- +
` ); - export const ImageTitle = new Template("Image Title", TemplatePosition.InnerTop, - `
-
{layout}
-
- {props.Document.title} -
-
` ); - - export const TextTitle = new Template("Text Title", TemplatePosition.InnerTop, + export const Title = new Template("Title", TemplatePosition.InnerTop, `
{props.Document.title} @@ -92,7 +84,7 @@ export namespace Templates {
`); } - export const TemplateList: Template[] = [TextTitle, Header, ImageTitle, Caption, Bullet]; + export const TemplateList: Template[] = [Title, Header, Caption, Bullet]; export function sortTemplates(a: Template, b: Template) { if (a.Position < b.Position) { return -1; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 8dc10bcd1..8a6764c58 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -20,6 +20,7 @@ import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import React = require("react"); import { Transform } from '../../util/Transform'; +import { SelectionManager } from '../../util/SelectionManager'; export interface TreeViewProps { @@ -32,6 +33,7 @@ export interface TreeViewProps { ScreenToLocalTransform: () => Transform; treeViewId: string; parentKey: string; + active: () => boolean; } export enum BulletType { @@ -69,7 +71,7 @@ class TreeView extends React.Component { @action onMouseLeave = () => { this._isOver = false; } onPointerEnter = (e: React.PointerEvent): void => { - this.props.document.libraryBrush = true; + this.props.active() && (this.props.document.libraryBrush = true); if (e.buttons === 1) { this._header!.current!.className = "treeViewItem-header"; document.addEventListener("pointermove", this.onDragMove, true); @@ -149,7 +151,10 @@ class TreeView extends React.Component {
); return (
{editableView(StrCast(this.props.document.title))} {openRight} @@ -225,18 +230,19 @@ class TreeView extends React.Component { while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1); } keys.map(key => { - let docList = DocListCast(this.props.document[key]); + let docList = Cast(this.props.document[key], listSpec(Doc)); let remDoc = (doc: Doc) => this.remove(doc, key); let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.document, key, doc, addBefore, before); let doc = Cast(this.props.document[key], Doc); - if (doc instanceof Doc || docList.length) { + if (doc instanceof Doc || docList) { if (!this._collapsed) { bulletType = BulletType.Collapsible; contentElement.push(
    {(key === "data") ? (null) : {key}}
    - {TreeView.GetChildElements(doc instanceof Doc ? [doc] : docList, this.props.treeViewId, key, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform)} + {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, key, addDoc, remDoc, this.move, + this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.active)}
); } else { @@ -266,11 +272,12 @@ class TreeView extends React.Component { move: DragManager.MoveFunction, dropAction: dropActionType, addDocTab: (doc: Doc, where: string) => void, - screenToLocalXf: () => Transform + screenToLocalXf: () => Transform, + active: () => boolean ) { return docs.filter(child => !child.excludeFromLibrary && (key !== "data" || !child.isMinimized)).map(child => ); + dropAction={dropAction} addDocTab={addDocTab} ScreenToLocalTransform={screenToLocalXf} parentKey={key} active={active} />); } } @@ -309,7 +316,8 @@ export class CollectionTreeView extends CollectionSubView(Document) { } let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before); let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc); - let childElements = TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.fieldKey, addDoc, this.remove, moveDoc, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform); + let childElements = TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.fieldKey, addDoc, this.remove, + moveDoc, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.active); return (
(Docu dst.nativeHeight = src.nativeHeight; } else { - const docs = await SearchUtil.Search(`data_l:"${destDoc[Id]}"`, true); - const views = docs.map(d => DocumentManager.Instance.getDocumentView(d)).filter(d => d).map(d => d as DocumentView); - DocUtils.MakeLink(sourceDoc, destDoc, views.length ? views[0].props.Document : undefined); + // const docs = await SearchUtil.Search(`data_l:"${destDoc[Id]}"`, true); + // const views = docs.map(d => DocumentManager.Instance.getDocumentView(d)).filter(d => d).map(d => d as DocumentView); + DocUtils.MakeLink(sourceDoc, destDoc, this.props.ContainingCollectionView ? this.props.ContainingCollectionView.props.Document : undefined); de.data.droppedDocuments.push(destDoc); } } diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index fe0da2e7a..8cb1db953 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -6,7 +6,7 @@ import { FieldValue } from "./Types"; import { RefField } from "./RefField"; import { ObjectField } from "./ObjectField"; import { action } from "mobx"; -import { Parent, OnUpdate, Update, Id } from "./FieldSymbols"; +import { Parent, OnUpdate, Update, Id, SelfProxy } from "./FieldSymbols"; import { ComputedField } from "../fields/ScriptField"; export const setter = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { @@ -86,7 +86,7 @@ export function deleteProperty(target: any, prop: string | number | symbol) { delete target[prop]; return true; } - target[prop] = undefined; + target[SelfProxy][prop] = undefined; return true; } -- cgit v1.2.3-70-g09d2 From df9aef6a2026a05c02c9b6b4b1e0a7b10b4ba244 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 10 Jun 2019 13:48:04 -0400 Subject: fixed text overlay from lingering --- src/client/views/MainOverlayTextBox.tsx | 20 ++++++++++++++------ src/client/views/nodes/FormattedTextBox.tsx | 18 +++++++++++------- 2 files changed, 25 insertions(+), 13 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 0eb3e9707..a0359419b 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -17,11 +17,12 @@ interface MainOverlayTextBoxProps { export class MainOverlayTextBox extends React.Component { public static Instance: MainOverlayTextBox; @observable _textXf: () => Transform = () => Transform.Identity(); - private _textFieldKey: string = "data"; + public TextFieldKey: string = "data"; private _textColor: string | null = null; private _textHideOnLeave?: boolean; private _textTargetDiv: HTMLDivElement | undefined; private _textProxyDiv: React.RefObject; + public TextDoc?: Doc; constructor(props: MainOverlayTextBoxProps) { super(props); @@ -29,9 +30,16 @@ export class MainOverlayTextBox extends React.Component MainOverlayTextBox.Instance = this; reaction(() => FormattedTextBox.InputBoxOverlay, (box?: FormattedTextBox) => { - let sxf = Utils.GetScreenTransform(box ? box.CurrentDiv : undefined); - if (box) this.setTextDoc(box.props.fieldKey, box.CurrentDiv, () => new Transform(-sxf.translateX, -sxf.translateY, 1 / sxf.scale)); - else this.setTextDoc(); + if (box) { + this.TextDoc = box.props.Document; + let sxf = Utils.GetScreenTransform(box ? box.CurrentDiv : undefined); + let xf = () => { box.props.ScreenToLocalTransform(); return new Transform(-sxf.translateX, -sxf.translateY, 1 / sxf.scale); }; + this.setTextDoc(box.props.fieldKey, box.CurrentDiv, xf) + } + else { + this.TextDoc = undefined; + this.setTextDoc(); + } }); } @@ -40,7 +48,7 @@ export class MainOverlayTextBox extends React.Component if (this._textTargetDiv) { this._textTargetDiv.style.color = this._textColor; } - this._textFieldKey = textFieldKey!; + this.TextFieldKey = textFieldKey!; this._textXf = tx ? tx : () => Transform.Identity(); this._textTargetDiv = div; this._textHideOnLeave = FormattedTextBox.InputBoxOverlay && FormattedTextBox.InputBoxOverlay.props.hideOnLeave; @@ -98,7 +106,7 @@ export class MainOverlayTextBox extends React.Component return
-
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 559a9fbfc..4325fd48c 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -28,6 +28,7 @@ import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); import { Id } from '../../../new_fields/FieldSymbols'; +import { MainOverlayTextBox } from '../MainOverlayTextBox'; library.add(faEdit); library.add(faSmile); @@ -181,7 +182,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this._editorView) { this._editorView.destroy(); } - this.setupEditor(config, this.props.Document);// MainOverlayTextBox.Instance.TextDoc); // bcz: not sure why, but the order of events is such that this.props.Document hasn't updated yet, so without forcing the editor to the MainOverlayTextBox, it will display the previously focused textbox + this.setupEditor(config, // bcz: not sure why, but the order of events is such that this.props.Document hasn't updated yet, so without forcing the editor to the MainOverlayTextBox, it will display the previously focused textbox + MainOverlayTextBox.Instance.TextDoc ? MainOverlayTextBox.Instance.TextDoc : this.props.Document, + MainOverlayTextBox.Instance.TextFieldKey ? MainOverlayTextBox.Instance.TextFieldKey : this.props.fieldKey); } ); } else { @@ -203,15 +206,15 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe field => field && this._editorView && !this._applyingChange && this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field))) ); - this.setupEditor(config, this.props.Document); + this.setupEditor(config, this.props.Document, this.props.fieldKey); } - private setupEditor(config: any, doc?: Doc) { - let field = doc ? Cast(doc[this.props.fieldKey], RichTextField) : undefined; - let startup = StrCast(this.props.Document.documentText); + private setupEditor(config: any, doc: Doc, fieldKey: string) { + let field = doc ? Cast(doc[fieldKey], RichTextField) : undefined; + let startup = StrCast(doc.documentText); startup = startup.startsWith("@@@") ? startup.replace("@@@", "") : ""; if (!startup && !field && doc) { - startup = StrCast(doc[this.props.fieldKey]); + startup = StrCast(doc[fieldKey]); } if (this._proseRef.current) { this._editorView = new EditorView(this._proseRef.current, { @@ -222,12 +225,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } }); if (startup) { - this.props.Document.proto!.documentText = undefined; + Doc.GetProto(doc).documentText = undefined; this._editorView.dispatch(this._editorView.state.tr.insertText(startup)); } } if (this.props.selectOnLoad) { + console.log("Sel on load " + this.props.Document.title + " " + doc!.title); this.props.select(false); this._editorView!.focus(); } -- cgit v1.2.3-70-g09d2 From 06d5bb5c65da6f4a115ebf8118989115420bccef Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 11 Jun 2019 10:21:42 -0400 Subject: cleaned up some drop() code with text. fixed linkview titling. changed dragging to not deselect source collection. --- src/client/util/SelectionManager.ts | 23 ++++++++++++++++------ .../views/collections/CollectionBaseView.tsx | 5 +++-- .../CollectionFreeFormLinkView.tsx | 5 +++-- src/client/views/nodes/FormattedTextBox.tsx | 22 --------------------- 4 files changed, 23 insertions(+), 32 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index ddad4b818..b26032b04 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -10,15 +10,23 @@ export namespace SelectionManager { @observable SelectedDocuments: Array = []; @action - SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { + SelectDoc(docView: DocumentView, ctrlPressed: boolean): void { // if doc is not in SelectedDocuments, add it if (!ctrlPressed) { this.DeselectAll(); } - if (manager.SelectedDocuments.indexOf(doc) === -1) { - manager.SelectedDocuments.push(doc); - doc.props.whenActiveChanged(true); + if (manager.SelectedDocuments.indexOf(docView) === -1) { + manager.SelectedDocuments.push(docView); + docView.props.whenActiveChanged(true); + } + } + @action + DeselectDoc(docView: DocumentView): void { + let ind = manager.SelectedDocuments.indexOf(docView); + if (ind !== -1) { + manager.SelectedDocuments.splice(ind, 1); + docView.props.whenActiveChanged(false); } } @action @@ -31,8 +39,11 @@ export namespace SelectionManager { const manager = new Manager(); - export function SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { - manager.SelectDoc(doc, ctrlPressed); + export function DeselectDoc(docView: DocumentView): void { + manager.DeselectDoc(docView); + } + export function SelectDoc(docView: DocumentView, ctrlPressed: boolean): void { + manager.SelectDoc(docView, ctrlPressed); } export function IsSelected(doc: DocumentView): boolean { diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index d120c3a0c..5238ad114 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -10,6 +10,7 @@ import { SelectionManager } from '../../util/SelectionManager'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; import './CollectionBaseView.scss'; +import { DocumentManager } from '../../util/DocumentManager'; export enum CollectionViewType { Invalid, @@ -129,7 +130,8 @@ export class CollectionBaseView extends React.Component { @action.bound removeDocument(doc: Doc): boolean { - SelectionManager.DeselectAll(); + let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView) + docView && SelectionManager.DeselectDoc(docView); const props = this.props; //TODO This won't create the field if it doesn't already exist const value = Cast(props.Document[props.fieldKey], listSpec(Doc), []); @@ -163,7 +165,6 @@ export class CollectionBaseView extends React.Component { return true; } if (this.removeDocument(doc)) { - SelectionManager.DeselectAll(); return addDocument(doc); } return false; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index ca7c99f28..ba7e6cf9e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -44,8 +44,9 @@ export class CollectionFreeFormLinkView extends React.Component text += StrCast(l.title) + "(" + StrCast(l.linkDescription) + "), "); - text = text.substr(0, text.length - 2); + let first = this.props.LinkDocs[0]; + if (this.props.LinkDocs.length === 1) text += first.title + (first.linkDescription ? "(" + StrCast(first.linkDescription) + ")" : ""); + else text = "-multiple-"; return ( <> ; private _inputReactionDisposer: Opt; @@ -136,25 +135,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - @undoBatch - @action - drop = async (e: Event, de: DragManager.DropEvent) => { - if (de.data instanceof DragManager.LinkDragData) { - let sourceDoc = de.data.linkSourceDocument; - let destDoc = this.props.Document; - - DocUtils.MakeLink(sourceDoc, destDoc); - de.data.droppedDocuments.push(destDoc); - e.stopPropagation(); - } - } - componentDidMount() { - if (this._ref.current) { - this._dropDisposer = DragManager.MakeDropTarget(this._ref.current, { - handlers: { drop: this.drop.bind(this) } - }); - } const config = { schema, inpRules, //these currently don't do anything, but could eventually be helpful @@ -250,9 +231,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this._proxyReactionDisposer) { this._proxyReactionDisposer(); } - if (this._dropDisposer) { - this._dropDisposer(); - } } onPointerDown = (e: React.PointerEvent): void => { -- cgit v1.2.3-70-g09d2