diff options
35 files changed, 1068 insertions, 183 deletions
diff --git a/package-lock.json b/package-lock.json index c4c623994..ad181758c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -372,6 +372,101 @@ "resolved": "https://registry.npmjs.org/@log4js-node/log4js-api/-/log4js-api-1.0.2.tgz", "integrity": "sha512-6SJfx949YEWooh/CUPpJ+F491y4BYJmknz4hUN1+RHvKoUEynKbRmhnwbk/VLmh4OthLLDNCyWXfbh4DG1cTXA==" }, + "@material-ui/core": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.0.tgz", + "integrity": "sha512-bYo9uIub8wGhZySHqLQ833zi4ZML+XCBE1XwJ8EuUVSpTWWG57Pm+YugQToJNFsEyiKFhPh8DPD0bgupz8n01g==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.10.0", + "@material-ui/system": "^4.9.14", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.10.2", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0", + "react-transition-group": "^4.4.0" + }, + "dependencies": { + "dom-helpers": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.4.tgz", + "integrity": "sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^2.6.7" + } + }, + "popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, + "react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + } + } + }, + "@material-ui/styles": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.10.0.tgz", + "integrity": "sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.9.6", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.0.3", + "jss-plugin-camel-case": "^10.0.3", + "jss-plugin-default-unit": "^10.0.3", + "jss-plugin-global": "^10.0.3", + "jss-plugin-nested": "^10.0.3", + "jss-plugin-props-sort": "^10.0.3", + "jss-plugin-rule-value-function": "^10.0.3", + "jss-plugin-vendor-prefixer": "^10.0.3", + "prop-types": "^15.7.2" + } + }, + "@material-ui/system": { + "version": "4.9.14", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.9.14.tgz", + "integrity": "sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.9.6", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" + }, + "@material-ui/utils": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.10.2.tgz", + "integrity": "sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + } + }, "@rkusa/linebreak": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@rkusa/linebreak/-/linebreak-1.0.0.tgz", @@ -853,6 +948,16 @@ "@types/prosemirror-view": "*" } }, + "@types/prosemirror-dev-tools": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/prosemirror-dev-tools/-/prosemirror-dev-tools-2.1.0.tgz", + "integrity": "sha512-OhnSaC4yrrEMLPRUkEWcHAIPVqgKlLkE4kISqL3cHeAYxASouSPvPMLqhBIbWkGwaozy43DjjVC1OXkxTo+y5Q==", + "dev": true, + "requires": { + "@types/prosemirror-state": "*", + "@types/prosemirror-view": "*" + } + }, "@types/prosemirror-history": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/prosemirror-history/-/prosemirror-history-1.0.1.tgz", @@ -1065,7 +1170,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==", - "dev": true, "requires": { "@types/react": "*" } @@ -2468,6 +2572,11 @@ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.0.tgz", "integrity": "sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA==" }, + "bowser": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.9.4.tgz", + "integrity": "sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==" + }, "boxen": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", @@ -2868,6 +2977,11 @@ "type-detect": "^4.0.5" } }, + "chain-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/chain-function/-/chain-function-1.0.1.tgz", + "integrity": "sha512-SxltgMwL9uCko5/ZCLiyG2B7R9fY4pDZUw7hJ4MhirdjBLosoDqkWABi3XMucddHdLiFJMb7PD2MZifZriuMTg==" + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2878,6 +2992,11 @@ "supports-color": "^5.3.0" } }, + "change-emitter": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz", + "integrity": "sha1-6LL+PX8at9aaMhma/5HqaTFAlRU=" + }, "character-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", @@ -3604,6 +3723,11 @@ "shallow-clone": "^3.0.0" } }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -4253,6 +4377,15 @@ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" }, + "css-in-js-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz", + "integrity": "sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA==", + "requires": { + "hyphenate-style-name": "^1.0.2", + "isobject": "^3.0.1" + } + }, "css-loader": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz", @@ -4307,6 +4440,15 @@ } } }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "css-what": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", @@ -7022,6 +7164,11 @@ } } }, + "hyphenate-style-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz", + "integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ==" + }, "i": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", @@ -7237,6 +7384,15 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "inline-style-prefixer": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-3.0.8.tgz", + "integrity": "sha1-hVG45bTVcyROZqNLBPfTIHaitTQ=", + "requires": { + "bowser": "^1.7.3", + "css-in-js-utils": "^2.0.0" + } + }, "inspect-function": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/inspect-function/-/inspect-function-0.2.2.tgz", @@ -7545,6 +7701,11 @@ "is-extglob": "^2.1.1" } }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + }, "is-installed-globally": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", @@ -7912,6 +8073,84 @@ "verror": "1.10.0" } }, + "jss": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.3.0.tgz", + "integrity": "sha512-B5sTRW9B6uHaUVzSo9YiMEOEp3UX8lWevU0Fsv+xtRnsShmgCfIYX44bTH8bPJe6LQKqEXku3ulKuHLbxBS97Q==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^2.6.5", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.3.0.tgz", + "integrity": "sha512-tadWRi/SLWqLK3EUZEdDNJL71F3ST93Zrl9JYMjV0QDqKPAl0Liue81q7m/nFUpnSTXczbKDy4wq8rI8o7WFqA==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "^10.3.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.3.0.tgz", + "integrity": "sha512-tT5KkIXAsZOSS9WDSe8m8lEHIjoEOj4Pr0WrG0WZZsMXZ1mVLFCSsD2jdWarQWDaRNyMj/I4d7czRRObhOxSuw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "^10.3.0" + } + }, + "jss-plugin-global": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.3.0.tgz", + "integrity": "sha512-etYTG/y3qIR/vxZnKY+J3wXwObyBDNhBiB3l/EW9/pE3WHE//BZdK8LFvQcrCO48sZW1Z6paHo6klxUPP7WbzA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "^10.3.0" + } + }, + "jss-plugin-nested": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.3.0.tgz", + "integrity": "sha512-qWiEkoXNEkkZ+FZrWmUGpf+zBsnEOmKXhkjNX85/ZfWhH9dfGxUCKuJFuOWFM+rjQfxV4csfesq4hY0jk8Qt0w==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "^10.3.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.3.0.tgz", + "integrity": "sha512-boetORqL/lfd7BWeFD3K+IyPqyIC+l3CRrdZr+NPq7Noqp+xyg/0MR7QisgzpxCEulk+j2CRcEUoZsvgPC4nTg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "^10.3.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.3.0.tgz", + "integrity": "sha512-7WiMrKIHH3rwxTuJki9+7nY11r1UXqaUZRhHvqTD4/ZE+SVhvtD5Tx21ivNxotwUSleucA/8boX+NF21oXzr5Q==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "^10.3.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.3.0.tgz", + "integrity": "sha512-sZQbrcZyP5V0ADjCLwUA1spVWoaZvM7XZ+2fSeieZFBj31cRsnV7X70FFDerMHeiHAXKWzYek+67nMDjhrZAVQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "^10.3.0" + } + }, "jstransformer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", @@ -7945,6 +8184,11 @@ "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz", "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw==" }, + "keycode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz", + "integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=" + }, "keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -8191,6 +8435,11 @@ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, "lodash.padend": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", @@ -8202,6 +8451,11 @@ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, "lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", @@ -8361,6 +8615,38 @@ "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" }, + "material-ui": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/material-ui/-/material-ui-0.20.2.tgz", + "integrity": "sha512-VeqgQkdvtK193w+FFvXDEwlVxI4rWk83eWbpYLeOIHDPWr3rbB9B075JRnJt/8IsI2X8q5Aia5W3+7m4KkleDg==", + "requires": { + "babel-runtime": "^6.23.0", + "inline-style-prefixer": "^3.0.8", + "keycode": "^2.1.8", + "lodash.merge": "^4.6.0", + "lodash.throttle": "^4.1.1", + "prop-types": "^15.5.7", + "react-event-listener": "^0.6.2", + "react-transition-group": "^1.2.1", + "recompose": "^0.26.0", + "simple-assign": "^0.1.0", + "warning": "^3.0.0" + }, + "dependencies": { + "react-transition-group": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-1.2.1.tgz", + "integrity": "sha512-CWaL3laCmgAFdxdKbhhps+c0HRGF4c+hdM4H23+FI1QBNUyx/AMeIJGWorehPNSaKnQNOAxL7PQmqMu78CDj3Q==", + "requires": { + "chain-function": "^1.0.0", + "dom-helpers": "^3.2.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.5.6", + "warning": "^3.0.0" + } + } + } + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -13878,6 +14164,26 @@ "prop-types": "^15.6.0" } }, + "react-event-listener": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.6.6.tgz", + "integrity": "sha512-+hCNqfy7o9wvO6UgjqFmBzARJS7qrNoda0VqzvOuioEpoEXKutiKuv92dSz6kP7rYLmyHPyYNLesi5t/aH1gfw==", + "requires": { + "@babel/runtime": "^7.2.0", + "prop-types": "^15.6.0", + "warning": "^4.0.1" + }, + "dependencies": { + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + } + } + }, "react-grid-layout": { "version": "0.18.3", "resolved": "https://registry.npmjs.org/react-grid-layout/-/react-grid-layout-0.18.3.tgz", @@ -14214,6 +14520,24 @@ "resolve": "^1.1.6" } }, + "recompose": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.26.0.tgz", + "integrity": "sha512-KwOu6ztO0mN5vy3+zDcc45lgnaUoaQse/a5yLVqtzTK13czSWnFGmXbQVmnoMgDkI5POd1EwIKSbjU1V7xdZog==", + "requires": { + "change-emitter": "^0.1.2", + "fbjs": "^0.8.1", + "hoist-non-react-statics": "^2.3.1", + "symbol-observable": "^1.0.4" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + } + } + }, "redent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", @@ -14978,6 +15302,11 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, + "simple-assign": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/simple-assign/-/simple-assign-0.1.0.tgz", + "integrity": "sha1-F/0wZqXz13OPUDIbsPFMooHMS6o=" + }, "simple-concat": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", @@ -15817,6 +16146,11 @@ "has-flag": "^3.0.0" } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -16112,6 +16446,11 @@ "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "tinycolor2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", diff --git a/package.json b/package.json index 2a08a6bf1..75dc817f5 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "@types/passport-local": "^1.0.33", "@types/pdfjs-dist": "^2.1.4", "@types/prosemirror-commands": "^1.0.1", + "@types/prosemirror-dev-tools": "^2.1.0", "@types/prosemirror-history": "^1.0.1", "@types/prosemirror-inputrules": "^1.0.2", "@types/prosemirror-keymap": "^1.0.2", @@ -120,6 +121,7 @@ "@hig/flyout": "^1.2.1", "@hig/theme-context": "^2.1.3", "@hig/theme-data": "^2.16.1", + "@material-ui/core": "^4.11.0", "@types/google-maps": "^3.2.2", "@types/webscopeio__react-textarea-autocomplete": "^4.6.1", "@webscopeio/react-textarea-autocomplete": "^4.7.0", @@ -171,6 +173,7 @@ "jsonschema": "^1.2.5", "libxmljs": "^0.19.7", "lodash": "^4.17.15", + "material-ui": "^0.20.2", "mobile-detect": "^1.4.4", "mobx": "^5.15.3", "mobx-react": "^5.3.5", diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 85da621e0..f81c25bab 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,4 +1,4 @@ -import { runInAction } from "mobx"; +import { runInAction, action } from "mobx"; import { extname, basename } from "path"; import { DateField } from "../../fields/DateField"; import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc"; @@ -866,6 +866,7 @@ export namespace DocUtils { export function MakeLinkToActiveAudio(doc: Doc) { DocUtils.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: doc }, { doc: d }, "audio link", "audio timeline")); } + export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", id?: string) { const sv = DocumentManager.Instance.getDocumentView(source.doc); if (sv && sv.props.ContainingCollectionDoc === target.doc) return; @@ -877,6 +878,7 @@ export namespace DocUtils { Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(self)"); Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(self)"); + return linkDoc; } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 02c3e55ed..4276e04e4 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -59,7 +59,6 @@ export class CurrentUserUtils { const queryTemplate = this.mobileButton({ title: "NEW MOBILE BUTTON", onClick: undefined, - _backgroundColor: "lightgrey" }, [this.ficon({ ignoreClick: true, diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 40a9d0c45..1667b2f65 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -271,7 +271,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const considerPush = isText && this.considerGoogleDocsPush; return <div className="documentButtonBar"> <div className="documentButtonBar-button"> - <DocumentLinksButton View={this.view0} AlwaysOn={true} /> + <DocumentLinksButton View={this.view0} AlwaysOn={true} InMenu={true} /> </div> <div className="documentButtonBar-button"> {this.templateButton} diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index ff8380965..34f666f62 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -79,7 +79,15 @@ export default class KeyManager { // MarqueeView.DragMarquee = !MarqueeView.DragMarquee; // bcz: this needs a better disclosure UI break; case "escape": + // if (DocumentLinksButton.StartLink) { + // if (DocumentLinksButton.StartLink.Document) { + // action((e: React.PointerEvent<HTMLDivElement>) => { + // Doc.UnBrushDoc(DocumentLinksButton.StartLink?.Document as Doc); + // }); + // } + // } DocumentLinksButton.StartLink = undefined; + const main = MainView.Instance; Doc.SetSelectedTool(InkTool.None); var doDeselect = true; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index fab1798e2..15f818d1f 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -4,7 +4,7 @@ import { faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, - faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, + faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faTimesCircle, faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faArrowsAlt, faQuoteLeft, faSortAmountDown, faAlignLeft, faAlignCenter, faAlignRight } from '@fortawesome/free-solid-svg-icons'; import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss'; @@ -59,6 +59,8 @@ import { DocumentManager } from '../util/DocumentManager'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { LinkMenu } from './linking/LinkMenu'; import { LinkDocPreview } from './nodes/LinkDocPreview'; +import { Fade } from '@material-ui/core'; +import { LinkCreatedBox } from './nodes/LinkCreatedBox'; @observer export class MainView extends React.Component { @@ -82,7 +84,6 @@ export class MainView extends React.Component { public isPointerDown = false; - componentDidMount() { DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType"]); // can play with these fields on someone else's @@ -138,7 +139,7 @@ export class MainView extends React.Component { } library.add(faTasks, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, - faTerminal, faToggleOn, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, fileSolid, + faTerminal, faToggleOn, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faTimesCircle, faWindowMaximize, faAddressCard, fileSolid, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faTrashAlt, faAngleRight, faBell, @@ -606,6 +607,7 @@ export class MainView extends React.Component { {this.mainContent} </GestureOverlay> <PreviewCursor /> + <LinkCreatedBox /> {DocumentLinksButton.EditLink ? <LinkMenu location={DocumentLinksButton.EditLinkLoc} docView={DocumentLinksButton.EditLink} addDocTab={DocumentLinksButton.EditLink.props.addDocTab} changeFlyout={emptyFunction} /> : (null)} {LinkDocPreview.LinkInfo ? <LinkDocPreview location={LinkDocPreview.LinkInfo.Location} backgroundColor={this.defaultBackgroundColors} linkDoc={LinkDocPreview.LinkInfo.linkDoc} linkSrc={LinkDocPreview.LinkInfo.linkSrc} href={LinkDocPreview.LinkInfo.href} diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss index 123a27deb..5ada79a28 100644 --- a/src/client/views/collections/CollectionLinearView.scss +++ b/src/client/views/collections/CollectionLinearView.scss @@ -1,12 +1,51 @@ @import "../globalCssVariables"; @import "../_nodeModuleOverrides"; -.collectionLinearView-outer{ +.collectionLinearView-outer { overflow: hidden; - height:100%; + height: 100%; + .collectionLinearView { - display:flex; + display: flex; height: 100%; + + >span { + background: $dark-color; + color: $light-color; + border-radius: 18px; + margin-right: 6px; + cursor: pointer; + } + + .bottomPopup-background { + padding-right: 14px; + height: 35; + transform: translate3d(6px, 5px, 0px); + padding-top: 6.5px; + padding-bottom: 7px; + padding-left: 5px; + } + + .bottomPopup-text { + display: inline; + white-space: nowrap; + padding-left: 8px; + padding-right: 4px; + vertical-align: middle; + font-size: 12.5px; + } + + .bottomPopup-exit { + display: inline; + white-space: nowrap; + padding-left: 8px; + padding-right: 8px; + vertical-align: middle; + background-color: lightgrey; + border-radius: 5.5px; + color: black; + } + >label { margin-top: "auto"; margin-bottom: "auto"; @@ -17,15 +56,15 @@ font-size: 12.5px; width: 18px; height: 18px; - margin-top:auto; - margin-bottom:auto; + margin-top: auto; + margin-bottom: auto; margin-right: 3px; cursor: pointer; transition: transform 0.2s; } label p { - padding-left:5px; + padding-left: 5px; } label:hover { @@ -36,6 +75,7 @@ >input { display: none; } + >input:not(:checked)~.collectionLinearView-content { display: none; } @@ -52,12 +92,14 @@ position: relative; margin-top: auto; - .collectionLinearView-docBtn, .collectionLinearView-docBtn-scalable { - position:relative; - margin:auto; + .collectionLinearView-docBtn, + .collectionLinearView-docBtn-scalable { + position: relative; + margin: auto; margin-left: 3px; transform-origin: center 80%; } + .collectionLinearView-docBtn-scalable:hover { transform: scale(1.15); } @@ -68,10 +110,10 @@ border-radius: 18px; font-size: 15px; } - + .collectionLinearView-round-button:hover { transform: scale(1.15); } } } -} +}
\ No newline at end of file diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx index f38eeaf41..7cbe5c19d 100644 --- a/src/client/views/collections/CollectionLinearView.tsx +++ b/src/client/views/collections/CollectionLinearView.tsx @@ -13,6 +13,8 @@ import { CollectionSubView } from './CollectionSubView'; import { DocumentView } from '../nodes/DocumentView'; import { documentSchema } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; +import { DocumentLinksButton } from '../nodes/DocumentLinksButton'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; type LinearDocument = makeInterface<[typeof documentSchema,]>; @@ -75,6 +77,18 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { return new Transform(-translateX, -translateY, 1); } + @action + exitLongLinks = () => { + if (DocumentLinksButton.StartLink) { + if (DocumentLinksButton.StartLink.Document) { + action((e: React.PointerEvent<HTMLDivElement>) => { + Doc.UnBrushDoc(DocumentLinksButton.StartLink?.Document as Doc); + }); + } + } + DocumentLinksButton.StartLink = undefined; + } + render() { const guid = Utils.GenerateGuid(); const flexDir: any = StrCast(this.Document.flexDirection); @@ -82,7 +96,12 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { const color = StrCast(this.props.Document.color, "white"); return <div className="collectionLinearView-outer"> <div className="collectionLinearView" ref={this.createDashEventsTarget} > - <label htmlFor={`${guid}`} title="Close Menu" style={{ background: backgroundColor === color ? "black" : backgroundColor }} + <label htmlFor={`${guid}`} title="Close Menu" style={{ + background: backgroundColor === color ? "black" : backgroundColor, + // width: "18px", height: "18px", fontSize: "12.5px", + // transition: this.props.Document.linearViewIsExpanded ? "transform 0.2s" : "transform 0.5s", + // transform: this.props.Document.linearViewIsExpanded ? "" : "rotate(45deg)" + }} onPointerDown={e => e.stopPropagation()} > <p>+</p> </label> @@ -130,6 +149,19 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { </div>; })} </div> + {DocumentLinksButton.StartLink ? <span className="bottomPopup-background" style={{ + background: backgroundColor === color ? "black" : backgroundColor + }} + onPointerDown={e => e.stopPropagation()} > + <span className="bottomPopup-text" > + Creating link from: {DocumentLinksButton.StartLink.title} </span> + <span className="bottomPopup-exit" onClick={this.exitLongLinks} + >Exit</span> + + {/* <FontAwesomeIcon icon="times-circle" size="lg" style={{ color: "red" }} + onClick={this.exitLongLinks} /> */} + + </span> : null} </div> </div>; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 10ebe571b..26abd2529 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -12,26 +12,29 @@ import { AclAddonly, AclReadonly, AclSym, DataSym, Doc, DocListCast, Field, Opt import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; +import { RichTextField } from '../../../fields/RichTextField'; import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, returnEmptyFilter } from '../../../Utils'; +import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { InteractionUtils } from '../../util/InteractionUtils'; +import { UndoManager } from '../../util/UndoManager'; import { ContextMenu } from "../ContextMenu"; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { ScriptBox } from '../ScriptBox'; import { Touchable } from '../Touchable'; -import { CollectionCarouselView } from './CollectionCarouselView'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; +import { CollectionCarouselView } from './CollectionCarouselView'; import { CollectionDockingView } from "./CollectionDockingView"; import { AddCustomFreeFormLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { CollectionGridView } from './collectionGrid/CollectionGridView'; import { CollectionLinearView } from './CollectionLinearView'; import CollectionMapView from './CollectionMapView'; import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; @@ -43,12 +46,8 @@ import { CollectionStaffView } from './CollectionStaffView'; import { SubCollectionViewProps } from './CollectionSubView'; import { CollectionTimeView } from './CollectionTimeView'; import { CollectionTreeView } from "./CollectionTreeView"; -import { CollectionGridView } from './collectionGrid/CollectionGridView'; import './CollectionView.scss'; import { CollectionViewBaseChrome } from './CollectionViewChromes'; -import { UndoManager } from '../../util/UndoManager'; -import { RichTextField } from '../../../fields/RichTextField'; -import { TextField } from '../../util/ProsemirrorCopy/prompt'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index c20f2162a..7f1fe7649 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -300,7 +300,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro onPointerDown={stopPropagation} onChange={this.viewChanged} value={StrCast(this.props.CollectionView.props.Document._viewType)}> - {Object.values(CollectionViewType).map(type => ["invalid", "docking"].includes(type) ? (null) : ( + {Object.values(CollectionViewType).map(type => [CollectionViewType.Invalid, CollectionViewType.Docking].includes(type) ? (null) : ( <option key={Utils.GenerateGuid()} className="collectionViewBaseChrome-viewOption" diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 21b0473c9..b81e400b3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,53 +1,51 @@ import { library } from "@fortawesome/fontawesome-svg-core"; -import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons"; +import { faEye } from "@fortawesome/free-regular-svg-icons"; import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, _allowStateChangesInsideComputed, trace } from "mobx"; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; -import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../fields/Doc"; -import { documentSchema, collectionSchema } from "../../../../fields/documentSchemas"; +import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../fields/Doc"; +import { collectionSchema, documentSchema } from "../../../../fields/documentSchemas"; import { Id } from "../../../../fields/FieldSymbols"; -import { InkData, InkField, InkTool, PointData } from "../../../../fields/InkField"; +import { InkData, InkField, InkTool } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { RichTextField } from "../../../../fields/RichTextField"; -import { createSchema, listSpec, makeInterface } from "../../../../fields/Schema"; -import { ScriptField, ComputedField } from "../../../../fields/ScriptField"; +import { createSchema, makeInterface } from "../../../../fields/Schema"; +import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { TraceMobx } from "../../../../fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; -import { aggregateBounds, intersectRect, returnOne, Utils, returnZero, returnFalse, numberRange } from "../../../../Utils"; +import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, Utils } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; +import { DocumentType } from "../../../documents/DocumentTypes"; import { DocumentManager } from "../../../util/DocumentManager"; import { DragManager, dropActionType } from "../../../util/DragManager"; import { HistoryUtil } from "../../../util/History"; import { InteractionUtils } from "../../../util/InteractionUtils"; import { SelectionManager } from "../../../util/SelectionManager"; +import { SnappingManager } from "../../../util/SnappingManager"; import { Transform } from "../../../util/Transform"; import { undoBatch, UndoManager } from "../../../util/UndoManager"; import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss"; +import { Timeline } from "../../animationtimeline/Timeline"; import { ContextMenu } from "../../ContextMenu"; -import { ContextMenuProps } from "../../ContextMenuItem"; +import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth } from "../../InkingStroke"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; -import { DocumentViewProps, DocumentView } from "../../nodes/DocumentView"; +import { DocumentLinksButton } from "../../nodes/DocumentLinksButton"; +import { DocumentViewProps } from "../../nodes/DocumentView"; import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox"; import { pageSchema } from "../../nodes/ImageBox"; -import PDFMenu from "../../pdf/PDFMenu"; import { CollectionDockingView } from "../CollectionDockingView"; import { CollectionSubView } from "../CollectionSubView"; -import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult, computerStarburstLayout, computerPassLayout } from "./CollectionFreeFormLayoutEngines"; +import { CollectionViewType } from "../CollectionView"; +import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); -import { CollectionViewType } from "../CollectionView"; -import { Timeline } from "../../animationtimeline/Timeline"; -import { SnappingManager } from "../../../util/SnappingManager"; -import { InkingStroke, ActiveArrowStart, ActiveArrowEnd, ActiveInkColor, ActiveFillColor, ActiveInkWidth, ActiveInkBezierApprox, ActiveDash } from "../../InkingStroke"; -import { DocumentType } from "../../../documents/DocumentTypes"; -import { DocumentLinksButton } from "../../nodes/DocumentLinksButton"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss index c372e7098..6468ccd3d 100644 --- a/src/client/views/linking/LinkMenu.scss +++ b/src/client/views/linking/LinkMenu.scss @@ -15,7 +15,7 @@ } .linkMenu-group { - border-bottom: 0.5px solid lightgray; + border-bottom: 0.5px solid lightgray; padding: 5px 0; @@ -30,9 +30,11 @@ p { background-color: lightgray; } + p.expand-one { width: calc(100% - 26px); } + .linkEditor-tableButton { display: block; } @@ -50,7 +52,4 @@ display: none; } } -} - - - +}
\ No newline at end of file diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index de1d60a09..c672511ac 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -10,6 +10,7 @@ import { LinkMenuGroup } from "./LinkMenuGroup"; import { faTrash } from '@fortawesome/free-solid-svg-icons'; import { library } from "@fortawesome/fontawesome-svg-core"; import { DocumentLinksButton } from "../nodes/DocumentLinksButton"; +import { LinkDocPreview } from "../nodes/LinkDocPreview"; library.add(faTrash); @@ -28,9 +29,16 @@ export class LinkMenu extends React.Component<Props> { @action onClick = (e: PointerEvent) => { + + LinkDocPreview.LinkInfo = undefined; + if (this._linkMenuRef?.contains(e.target as any)) { DocumentLinksButton.EditLink = undefined; } + + if (this._linkMenuRef && !this._linkMenuRef.contains(e.target as any)) { + DocumentLinksButton.EditLink = undefined; + } } @action componentDidMount() { @@ -70,7 +78,8 @@ export class LinkMenu extends React.Component<Props> { render() { const sourceDoc = this.props.docView.props.Document; const groups: Map<string, Doc[]> = LinkManager.Instance.getRelatedGroupedLinks(sourceDoc); - return <div className="linkMenu-list" ref={(r) => this._linkMenuRef = r} style={{ left: this.props.location[0], top: this.props.location[1] }}> + return <div className="linkMenu-list" + ref={(r) => this._linkMenuRef = r} style={{ left: this.props.location[0], top: this.props.location[1] }}> {!this._editingLink ? this.renderAllGroups(groups) : <LinkEditor sourceDoc={this.props.docView.props.Document} linkDoc={this._editingLink} showLinks={action(() => this._editingLink = undefined)} /> diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index 89deb3a55..7892d381b 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -80,11 +80,11 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> { return ( <div className="linkMenu-group"> - <div className="linkMenu-group-name"> + {/* <div className="linkMenu-group-name"> <p ref={this._drag} onPointerDown={this.onLinkButtonDown} className={this.props.groupType === "*" || this.props.groupType === "" ? "" : "expand-one"} > {this.props.groupType}:</p> {this.props.groupType === "*" || this.props.groupType === "" ? <></> : this.viewGroupAsTable(this.props.groupType)} - </div> + </div> */} <div className="linkMenu-group-wrapper"> {groupItems} </div> diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss index fd0954f65..e3ce69cd7 100644 --- a/src/client/views/linking/LinkMenuItem.scss +++ b/src/client/views/linking/LinkMenuItem.scss @@ -5,7 +5,7 @@ position: relative; display: flex; font-size: 12px; - + .linkMenu-name { position: relative; @@ -22,7 +22,7 @@ .linkMenu-item-content { width: 100%; } - + .link-metadata { padding: 0 10px 0 16px; margin-bottom: 4px; @@ -35,11 +35,13 @@ .linkMenu-item-buttons { display: flex; } + .linkMenu-item-content { &.expand-two p { width: calc(100% - 52px); background-color: lightgray; } + &.expand-three p { width: calc(100% - 84px); background-color: lightgray; @@ -49,11 +51,11 @@ } .linkMenu-item-buttons { - display: none; position: absolute; top: 50%; right: 0; transform: translateY(-50%); + display: none; .button { width: 20px; @@ -61,7 +63,6 @@ margin: 0; margin-right: 6px; border-radius: 50%; - cursor: pointer; pointer-events: auto; background-color: $dark-color; color: $light-color; @@ -80,8 +81,10 @@ &:last-child { margin-right: 0; } + &:hover { background: $main-accent; + cursor: grab; } } }
\ No newline at end of file diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index edc18b6a9..04cd83ee0 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faArrowRight, faChevronDown, faChevronUp, faEdit, faEye, faTimes } from '@fortawesome/free-solid-svg-icons'; +import { faArrowRight, faChevronDown, faChevronUp, faEdit, faEye, faTimes, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from "mobx-react"; @@ -13,7 +13,9 @@ import React = require("react"); import { DocumentManager } from '../../util/DocumentManager'; import { setupMoveUpEvents, emptyFunction } from '../../../Utils'; import { DocumentView } from '../nodes/DocumentView'; -library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp); +import { DocumentLinksButton } from '../nodes/DocumentLinksButton'; +import { LinkDocPreview } from '../nodes/LinkDocPreview'; +library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp, faPencilAlt); interface LinkMenuItemProps { @@ -69,6 +71,8 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { private _eleClone: any; _editRef = React.createRef<HTMLDivElement>(); + _buttonRef = React.createRef<HTMLDivElement>(); + @observable private _showMore: boolean = false; @action toggleShowMore(e: React.PointerEvent) { e.stopPropagation(); this._showMore = !this._showMore; } @@ -95,6 +99,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { return (<div className="link-metadata">{mdRows}</div>); } + @action onLinkButtonDown = (e: React.PointerEvent): void => { this._downX = e.clientX; this._downY = e.clientY; @@ -104,6 +109,10 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { document.addEventListener("pointermove", this.onLinkButtonMoved); document.removeEventListener("pointerup", this.onLinkButtonUp); document.addEventListener("pointerup", this.onLinkButtonUp); + + if (this._buttonRef && this._buttonRef.current?.contains(e.target as any)) { + LinkDocPreview.LinkInfo = undefined; + } } onLinkButtonUp = (e: PointerEvent): void => { @@ -124,7 +133,10 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { e.stopPropagation(); } + @action onContextMenu = (e: React.MouseEvent) => { + DocumentLinksButton.EditLink = undefined; + LinkDocPreview.LinkInfo = undefined; e.preventDefault(); ContextMenu.Instance.addItem({ description: "Follow Default Link", event: () => this.followDefault(), icon: "arrow-right" }); ContextMenu.Instance.displayMenu(e.clientX, e.clientY); @@ -132,9 +144,20 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { @action.bound async followDefault() { + console.log("FOLLOWWW"); + DocumentLinksButton.EditLink = undefined; + LinkDocPreview.LinkInfo = undefined; DocumentManager.Instance.FollowLink(this.props.linkDoc, this.props.sourceDoc, doc => this.props.addDocTab(doc, "onRight"), false); } + @action + deleteLink = (): void => { + LinkManager.Instance.deleteLink(this.props.linkDoc); + //this.props.showLinks(); + LinkDocPreview.LinkInfo = undefined; + DocumentLinksButton.EditLink = undefined; + } + render() { const keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType); const canExpand = keys ? keys.length > 0 : false; @@ -142,13 +165,25 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { return ( <div className="linkMenu-item"> <div className={canExpand ? "linkMenu-item-content expand-three" : "linkMenu-item-content expand-two"}> - <div ref={this._drag} className="linkMenu-name" title="drag to view target. click to customize." onPointerDown={this.onLinkButtonDown}> + <div ref={this._drag} className="linkMenu-name" //title="drag to view target. click to customize." + onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)} + onPointerEnter={action(e => this.props.linkDoc && (LinkDocPreview.LinkInfo = { + addDocTab: this.props.addDocTab, + linkSrc: this.props.sourceDoc, + linkDoc: this.props.linkDoc, + Location: [e.clientX, e.clientY + 20] + }))} + onPointerDown={this.onLinkButtonDown}> <p >{StrCast(this.props.destinationDoc.title)}</p> - <div className="linkMenu-item-buttons"> + <div className="linkMenu-item-buttons" ref={this._buttonRef} > {canExpand ? <div title="Show more" className="button" onPointerDown={e => this.toggleShowMore(e)}> <FontAwesomeIcon className="fa-icon" icon={this._showMore ? "chevron-up" : "chevron-down"} size="sm" /></div> : <></>} - <div title="Edit link" className="button" ref={this._editRef} onPointerDown={this.onEdit}><FontAwesomeIcon className="fa-icon" icon="edit" size="sm" /></div> - <div title="Follow link" className="button" onClick={this.followDefault} onContextMenu={this.onContextMenu}> + + {/* <div title="Edit link" className="button" ref={this._editRef} onPointerDown={this.onEdit}> + <FontAwesomeIcon className="fa-icon" icon="pencil-alt" size="sm" /></div> */} + <div title="Delete link" className="button" onPointerDown={this.deleteLink}> + <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" /></div> + <div title="Follow link" className="button" onPointerDown={this.followDefault} onContextMenu={this.onContextMenu}> <FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" /> </div> </div> diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index 810a824cf..acf6b1636 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -3,7 +3,7 @@ border-radius: inherit; width: 100%; height: 100%; - position: absolute; + position: relative; z-index: 0; pointer-events: none; diff --git a/src/client/views/nodes/DocumentLinksButton.scss b/src/client/views/nodes/DocumentLinksButton.scss index 484f8c469..b58603978 100644 --- a/src/client/views/nodes/DocumentLinksButton.scss +++ b/src/client/views/nodes/DocumentLinksButton.scss @@ -23,7 +23,7 @@ &:hover { background: deepskyblue; transform: scale(1.05); - cursor: default; + cursor: grab; } } .documentLinksButton { diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 3940b7a98..bfd860f65 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -10,6 +10,7 @@ import React = require("react"); import { DocUtils } from "../../documents/Documents"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { LinkDocPreview } from "./LinkDocPreview"; +import { LinkCreatedBox } from "./LinkCreatedBox"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -18,11 +19,14 @@ interface DocumentLinksButtonProps { View: DocumentView; Offset?: number[]; AlwaysOn?: boolean; + InMenu?: boolean; } @observer export class DocumentLinksButton extends React.Component<DocumentLinksButtonProps, {}> { private _linkButton = React.createRef<HTMLDivElement>(); + @observable public static StartLink: DocumentView | undefined; + @action onLinkButtonMoved = (e: PointerEvent) => { if (this._linkButton.current !== null) { @@ -50,30 +54,73 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp return false; } - @observable static StartLink: DocumentView | undefined; onLinkButtonDown = (e: React.PointerEvent): void => { setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, action((e, doubleTap) => { - if (doubleTap) { + if (doubleTap && this.props.InMenu) { + //action(() => Doc.BrushDoc(this.props.View.Document)); DocumentLinksButton.StartLink = this.props.View; - } else { + } else if (!!!this.props.InMenu) { DocumentLinksButton.EditLink = this.props.View; DocumentLinksButton.EditLinkLoc = [e.clientX + 10, e.clientY]; } })); } + + @action + onLinkClick = (e: React.MouseEvent): void => { + if (this.props.InMenu) { + DocumentLinksButton.StartLink = this.props.View; + //action(() => Doc.BrushDoc(this.props.View.Document)); + } else if (!!!this.props.InMenu) { + DocumentLinksButton.EditLink = this.props.View; + DocumentLinksButton.EditLinkLoc = [e.clientX + 10, e.clientY]; + } + } + + @action completeLink = (e: React.PointerEvent): void => { setupMoveUpEvents(this, e, returnFalse, emptyFunction, action((e, doubleTap) => { if (doubleTap) { if (DocumentLinksButton.StartLink === this.props.View) { DocumentLinksButton.StartLink = undefined; + // action((e: React.PointerEvent<HTMLDivElement>) => { + // Doc.UnBrushDoc(this.props.View.Document); + // }); } else { DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View && DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.props.View.props.Document }, "long drag"); + + runInAction(() => { + LinkCreatedBox.popupX = e.screenX; + LinkCreatedBox.popupY = e.screenY - 120; + LinkCreatedBox.linkCreated = true; + setTimeout(action(() => { LinkCreatedBox.linkCreated = false; }), 2500); + }); } } })); } + @action + finishLinkClick = (e: React.MouseEvent) => { + if (DocumentLinksButton.StartLink === this.props.View) { + DocumentLinksButton.StartLink = undefined; + // action((e: React.PointerEvent<HTMLDivElement>) => { + // Doc.UnBrushDoc(this.props.View.Document); + // }); + } else { + DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View && + DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink.props.Document }, { doc: this.props.View.props.Document }, "long drag"); + + runInAction(() => { + LinkCreatedBox.popupX = e.screenX; + LinkCreatedBox.popupY = e.screenY - 120; + LinkCreatedBox.linkCreated = true; + setTimeout(action(() => { LinkCreatedBox.linkCreated = false; }), 2500); + }); + } + } + @observable public static EditLink: DocumentView | undefined; public static EditLinkLoc: number[] = [0, 0]; @@ -83,19 +130,26 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp const links = DocListCast(this.props.View.props.Document.links); return (!links.length || links[0].hidden) && !this.props.AlwaysOn ? (null) : <div title="Drag(create link) Tap(view links)" ref={this._linkButton} style={{ minWidth: 20, minHeight: 20, position: "absolute", left: this.props.Offset?.[0] }}> - <div className={"documentLinksButton"} style={{ backgroundColor: DocumentLinksButton.StartLink ? "transparent" : "" }} - onPointerDown={this.onLinkButtonDown} - onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)} - onPointerEnter={action(e => links.length && (LinkDocPreview.LinkInfo = { - addDocTab: this.props.View.props.addDocTab, - linkSrc: this.props.View.props.Document, - linkDoc: links[0], - Location: [e.clientX, e.clientY + 20] - }))} > - {links.length ? links.length : <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" />} + <div className={"documentLinksButton"} style={{ + backgroundColor: DocumentLinksButton.StartLink ? "transparent" : "", + width: this.props.InMenu ? "20px" : "30px", height: this.props.InMenu ? "20px" : "30px", fontWeight: "bold" + }} + onPointerDown={this.onLinkButtonDown} onClick={this.onLinkClick} + // onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)} + // onPointerEnter={action(e => links.length && (LinkDocPreview.LinkInfo = { + // addDocTab: this.props.View.props.addDocTab, + // linkSrc: this.props.View.props.Document, + // linkDoc: links[0], + // Location: [e.clientX, e.clientY + 20] + // }))} + > + {links.length && !!!this.props.InMenu ? links.length : <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" />} </div> - {DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-endLink"} onPointerDown={this.completeLink} /> : (null)} - {DocumentLinksButton.StartLink === this.props.View ? <div className={"documentLinksButton-startLink"} /> : (null)} + {DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-endLink"} + style={{ width: this.props.InMenu ? "20px" : "30px", height: this.props.InMenu ? "20px" : "30px" }} + onPointerDown={this.completeLink} onClick={e => this.finishLinkClick(e)} /> : (null)} + {DocumentLinksButton.StartLink === this.props.View ? <div className={"documentLinksButton-startLink"} + style={{ width: this.props.InMenu ? "20px" : "30px", height: this.props.InMenu ? "20px" : "30px" }} /> : (null)} </div>; } render() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 37d8df47d..297a9f2a5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -42,6 +42,7 @@ import { RadialMenu } from './RadialMenu'; import React = require("react"); import { DocumentLinksButton } from './DocumentLinksButton'; import { MobileInterface } from '../../../mobile/MobileInterface'; +import { LinkCreatedBox } from './LinkCreatedBox'; library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight, fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale, @@ -116,6 +117,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; private holdDisposer?: InteractionUtils.MultiTouchEventDisposer; + public get title() { return this.props.Document.title; } public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive public get ContentDiv() { return this._mainCont.current; } get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); } @@ -640,12 +642,27 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu e.stopPropagation(); de.complete.annoDragData.linkedToDoc = true; + runInAction(() => { + LinkCreatedBox.popupX = de.x; + LinkCreatedBox.popupY = de.y; + LinkCreatedBox.linkCreated = true; + setTimeout(action(() => { LinkCreatedBox.linkCreated = false; }), 2500); + }); + DocUtils.MakeLink({ doc: de.complete.annoDragData.annotationDocument }, { doc: this.props.Document }, "link"); } if (de.complete.linkDragData) { e.stopPropagation(); // 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); + + runInAction(() => { + LinkCreatedBox.popupX = de.x; + LinkCreatedBox.popupY = de.y; + LinkCreatedBox.linkCreated = true; + setTimeout(action(() => { LinkCreatedBox.linkCreated = false; }), 2500); + }); + de.complete.linkDragData.linkSourceDocument !== this.props.Document && (de.complete.linkDragData.linkDocument = DocUtils.MakeLink({ doc: de.complete.linkDragData.linkSourceDocument }, { doc: this.props.Document }, `link`)); // TODODO this is where in text links get passed @@ -1191,7 +1208,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu id={this.props.Document[Id]} ref={this._mainCont} onKeyDown={this.onKeyDown} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick} - onPointerEnter={action(() => Doc.BrushDoc(this.props.Document))} + onPointerEnter={action(() => { Doc.BrushDoc(this.props.Document); })} onPointerLeave={action((e: React.PointerEvent<HTMLDivElement>) => { let entered = false; const target = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y); @@ -1200,7 +1217,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu entered = true; } } + // if (this.props.Document !== DocumentLinksButton.StartLink?.Document) { !entered && Doc.UnBrushDoc(this.props.Document); + //} + })} style={{ transformOrigin: this._animateScalingTo ? "center center" : undefined, diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index 15148d01d..c1b95b308 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -2,7 +2,7 @@ border-radius: inherit; width: 100%; height: 100%; - position: absolute; + position: relative; transform-origin: top left; .imageBox-fader { diff --git a/src/client/views/nodes/LinkAnchorBox.scss b/src/client/views/nodes/LinkAnchorBox.scss index 710f2178b..42ef2958e 100644 --- a/src/client/views/nodes/LinkAnchorBox.scss +++ b/src/client/views/nodes/LinkAnchorBox.scss @@ -1,4 +1,5 @@ -.linkAnchorBox-cont, .linkAnchorBox-cont-small { +.linkAnchorBox-cont, +.linkAnchorBox-cont-small { cursor: default; position: absolute; width: 15; @@ -24,6 +25,6 @@ } .linkAnchorBox-cont-small { - width:5px; - height:5px; + width: 5px; + height: 5px; }
\ No newline at end of file diff --git a/src/client/views/nodes/LinkCreatedBox.scss b/src/client/views/nodes/LinkCreatedBox.scss new file mode 100644 index 000000000..3cbd38b55 --- /dev/null +++ b/src/client/views/nodes/LinkCreatedBox.scss @@ -0,0 +1,21 @@ +.linkCreatedBox-fade { + border: 1px solid rgb(100, 100, 100); + + + width: auto; + position: absolute; + + height: auto; + z-index: 10000; + border-radius: 13px; + font-size: 13px; + white-space: nowrap; + + color: rgb(100, 100, 100); + background-color: rgba(250, 250, 250, 0.85); + padding-top: 6.5px; + padding-bottom: 6.5px; + font-weight: bold; + padding-left: 9px; + padding-right: 9px; +}
\ No newline at end of file diff --git a/src/client/views/nodes/LinkCreatedBox.tsx b/src/client/views/nodes/LinkCreatedBox.tsx new file mode 100644 index 000000000..d157d3fca --- /dev/null +++ b/src/client/views/nodes/LinkCreatedBox.tsx @@ -0,0 +1,31 @@ +import React = require("react"); +import { observer } from "mobx-react"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { makeInterface } from "../../../fields/Schema"; +import "./LinkCreatedBox.scss"; +import { observable, action } from "mobx"; +import { Fade } from "@material-ui/core"; + + +@observer +export class LinkCreatedBox extends React.Component<{}> { + + @observable public static linkCreated: boolean = false; + @observable public static popupX: number = 600; + @observable public static popupY: number = 250; + + @action + public static changeLinkCreated = () => { + LinkCreatedBox.linkCreated = !LinkCreatedBox.linkCreated; + } + + render() { + return <Fade in={LinkCreatedBox.linkCreated}> + <div className="linkCreatedBox-fade" + style={{ + left: LinkCreatedBox.popupX ? LinkCreatedBox.popupX : 600, + top: LinkCreatedBox.popupY ? LinkCreatedBox.popupY : 250, + }}>Link Created</div> + </Fade>; + } +}
\ No newline at end of file diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index e8a08abb5..197dc8df4 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -10,6 +10,11 @@ import { Transform } from "../../util/Transform"; import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; import React = require("react"); import { DocumentView } from './DocumentView'; +import { sortAndDeduplicateDiagnostics } from 'typescript'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { LinkManager } from '../../util/LinkManager'; +import { DocumentLinksButton } from './DocumentLinksButton'; +import { ContextMenu } from '../ContextMenu'; interface Props { linkDoc?: Doc; @@ -24,6 +29,31 @@ export class LinkDocPreview extends React.Component<Props> { @observable public static LinkInfo: Opt<{ linkDoc?: Doc; addDocTab: (document: Doc, where: string) => boolean, linkSrc: Doc; href?: string; Location: number[] }>; @observable _targetDoc: Opt<Doc>; @observable _toolTipText = ""; + _editRef = React.createRef<HTMLDivElement>(); + + @action + deleteLink = (): void => { + this.props.linkDoc ? LinkManager.Instance.deleteLink(this.props.linkDoc) : null; + //this.props.showLinks(); + LinkDocPreview.LinkInfo = undefined; + DocumentLinksButton.EditLink = undefined; + } + + @action + onContextMenu = (e: React.MouseEvent) => { + DocumentLinksButton.EditLink = undefined; + LinkDocPreview.LinkInfo = undefined; + e.preventDefault(); + ContextMenu.Instance.addItem({ description: "Follow Default Link", event: () => this.followDefault(), icon: "arrow-right" }); + ContextMenu.Instance.displayMenu(e.clientX, e.clientY); + } + + @action.bound + async followDefault() { + DocumentLinksButton.EditLink = undefined; + LinkDocPreview.LinkInfo = undefined; + this._targetDoc ? DocumentManager.Instance.FollowLink(this.props.linkDoc, this._targetDoc, doc => this.props.addDocTab(doc, "onRight"), false) : null; + } componentDidUpdate() { this.updatePreview(); } componentDidMount() { this.updatePreview(); } @@ -56,15 +86,30 @@ export class LinkDocPreview extends React.Component<Props> { this.props.addDocTab(Docs.Create.WebDocument(this.props.href, { title: this.props.href, _width: 200, _height: 400, UseCors: true }), "onRight"); } } - width = () => Math.min(350, NumCast(this._targetDoc?.[WidthSym](), 350)); - height = () => Math.min(350, NumCast(this._targetDoc?.[HeightSym](), 350)); + width = () => Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225)); + height = () => Math.min(225, NumCast(this._targetDoc?.[HeightSym](), 225)); @computed get targetDocView() { return !this._targetDoc ? - <div style={{ pointerEvents: "all", maxWidth: 350, maxHeight: 250, width: "100%", height: "100%", overflow: "hidden" }}> + <div style={{ + pointerEvents: "all", maxWidth: 225, maxHeight: 225, width: "100%", height: "100%", + overflow: "hidden" + }}> <div style={{ width: "100%", height: "100%", textOverflow: "ellipsis", }} onPointerDown={this.pointerDown}> {this._toolTipText} </div> </div> : + // <div style={{ + // border: "6px solid white", + // }}> + // <div style={{ backgroundColor: "white" }}> {this._targetDoc.title} + // <div className="wrapper" style={{ float: "right" }}> + // <div title="Delete link" className="button" style={{ display: "inline" }} ref={this._editRef} onPointerDown={this.deleteLink}> + // <FontAwesomeIcon className="fa-icon" icon="trash" size="sm" /></div> + // <div title="Follow link" className="button" style={{ display: "inline" }} onClick={this.followDefault} onContextMenu={this.onContextMenu}> + // <FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" /> + // </div> + // </div> + // </div> <ContentFittingDocumentView Document={this._targetDoc} LibraryPath={emptyPath} @@ -92,6 +137,7 @@ export class LinkDocPreview extends React.Component<Props> { NativeWidth={returnZero} NativeHeight={returnZero} />; + //</div>; } render() { @@ -99,7 +145,7 @@ export class LinkDocPreview extends React.Component<Props> { style={{ position: "absolute", left: this.props.location[0], top: this.props.location[1], width: this.width(), height: this.height(), - boxShadow: "black 2px 2px 1em" + boxShadow: "black 2px 2px 1em", zIndex: 1000 }}> {this.targetDocView} </div>; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss index 0a094ba6a..afdd8fea2 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss @@ -303,27 +303,26 @@ footnote::after { font-family: inherit; } ol { - margin-left: 1em; font-family: inherit; } - .bullet { p {display: inline-block; font-family: inherit} margin-left: 0; } - .bullet1 { p {display: inline-block; font-family: inherit} } - .bullet2,.bullet3,.bullet4,.bullet5,.bullet6 { p {display: inline-block; font-family: inherit} font-size: smaller; } + .bullet { p { font-family: inherit} margin-left: 0; } + .bullet1 { p { font-family: inherit} } + .bullet2,.bullet3,.bullet4,.bullet5,.bullet6 { p { font-family: inherit} font-size: smaller; } .decimal1-ol { counter-reset: deci1; p {display: inline-block; font-family: inherit} margin-left: 0; } - .decimal2-ol { counter-reset: deci2; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 1em;} - .decimal3-ol { counter-reset: deci3; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 2em;} - .decimal4-ol { counter-reset: deci4; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 3em;} + .decimal2-ol { counter-reset: deci2; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 2.1em;} + .decimal3-ol { counter-reset: deci3; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 2.85em;} + .decimal4-ol { counter-reset: deci4; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 3.85em;} .decimal5-ol { counter-reset: deci5; p {display: inline-block; font-family: inherit} font-size: smaller; } .decimal6-ol { counter-reset: deci6; p {display: inline-block; font-family: inherit} font-size: smaller; } .decimal7-ol { counter-reset: deci7; p {display: inline-block; font-family: inherit} font-size: smaller; } .multi1-ol { counter-reset: multi1; p {display: inline-block; font-family: inherit} margin-left: 0; padding-left: 1.2em } - .multi2-ol { counter-reset: multi2; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 1.4em;} - .multi3-ol { counter-reset: multi3; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 2em;} - .multi4-ol { counter-reset: multi4; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 3.4em;} + .multi2-ol { counter-reset: multi2; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 2em;} + .multi3-ol { counter-reset: multi3; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 2.85em;} + .multi4-ol { counter-reset: multi4; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 3.85em;} - .bullet:before, .bullet1:before, .bullet2:before, .bullet3:before, .bullet4:before, .bullet5:before { transition: 0.5s; display: inline-block; vertical-align: top; margin-left: -1em; width: 1em; content:" " } + //.bullet:before, .bullet1:before, .bullet2:before, .bullet3:before, .bullet4:before, .bullet5:before { transition: 0.5s; display: inline-block; vertical-align: top; margin-left: -1em; width: 1em; content:" " } .decimal1:before { transition: 0.5s;counter-increment: deci1; display: inline-block; vertical-align: top; margin-left: -1em; width: 1em; content: counter(deci1) ". "; } .decimal2:before { transition: 0.5s;counter-increment: deci2; display: inline-block; vertical-align: top; margin-left: -2.1em; width: 2.1em; content: counter(deci1) "."counter(deci2) ". "; } @@ -333,7 +332,7 @@ footnote::after { .decimal6:before { transition: 0.5s;counter-increment: deci6; display: inline-block; vertical-align: top; margin-left: -2em; width: 6em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) ". "; } .decimal7:before { transition: 0.5s;counter-increment: deci7; display: inline-block; vertical-align: top; margin-left: -2em; width: 7em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) "."counter(deci7) ". "; } - .multi1:before { transition: 0.5s;counter-increment: multi1; display: inline-block; vertical-align: top; margin-left: -1em; width: 1.2em; content: counter(multi1, upper-alpha) ". "; } + .multi1:before { transition: 0.5s;counter-increment: multi1; display: inline-block; vertical-align: top; margin-left: -1.3em; width: 1.2em; content: counter(multi1, upper-alpha) ". "; } .multi2:before { transition: 0.5s;counter-increment: multi2; display: inline-block; vertical-align: top; margin-left: -2em; width: 2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) ". "; } .multi3:before { transition: 0.5s;counter-increment: multi3; display: inline-block; vertical-align: top; margin-left: -2.85em; width:2.85em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) ". "; } .multi4:before { transition: 0.5s;counter-increment: multi4; display: inline-block; vertical-align: top; margin-left: -4.2em; width: 4.2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) "."counter(multi4, lower-roman) ". "; } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 69708e7a0..fc63dfbf5 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -59,6 +59,7 @@ import { FieldView, FieldViewProps } from "../FieldView"; import "./FormattedTextBox.scss"; import { FormattedTextBoxComment, formattedTextBoxCommentPlugin, findLinkMark } from './FormattedTextBoxComment'; import React = require("react"); +import { DocumentManager } from '../../../util/DocumentManager'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -1031,6 +1032,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp _downX = 0; _downY = 0; _break = false; + _collapsed = false; onPointerDown = (e: React.PointerEvent): void => { if (this._recording && !e.ctrlKey && e.button === 0) { this.stopDictation(true); @@ -1079,6 +1081,40 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } @action + onDoubleClick = (e: React.MouseEvent): void => { + + this.doLinkOnDeselect(); + FormattedTextBox._downEvent = true; + FormattedTextBoxComment.textBox = this; + if (this.props.onClick && e.button === 0 && !this.props.isSelected(false)) { + e.preventDefault(); + } + if (e.button === 0 && this.props.isSelected(true) && !e.altKey && !e.ctrlKey && !e.metaKey) { + if (e.clientX < this.ProseRef!.getBoundingClientRect().right) { // stop propagation if not in sidebar + e.stopPropagation(); // if the text box is selected, then it consumes all down events + } + } + if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { + e.preventDefault(); + } + FormattedTextBoxComment.Hide(); + if (FormattedTextBoxComment.linkDoc) { + if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { + this.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight"); + } else { + DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, this.props.Document, + (doc: Doc, followLinkLocation: string) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); + } + } + + (e.nativeEvent as any).formattedHandled = true; + + if (e.buttons === 1 && this.props.isSelected(true) && !e.altKey) { + e.stopPropagation(); + } + } + + @action onFocused = (e: React.FocusEvent): void => { FormattedTextBox.FocusedBox = this; this.tryUpdateHeight(); @@ -1111,9 +1147,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp static _bulletStyleSheet: any = addStyleSheet(); static _userStyleSheet: any = addStyleSheet(); - + _forceUncollapse = true; // if the cursor doesn't move between clicks, then the selection will disappear for some reason. This flags the 2nd click as happening on a selection which allows bullet points to toggle + _forceDownNode: Node | undefined; onClick = (e: React.MouseEvent): void => { - if ((this._editorView!.root as any).getSelection().isCollapsed) { // this is a hack to allow the cursor to be placed at the end of a document when the document ends in an inline dash comment. Apparently Chrome on Windows has a bug/feature which breaks this when clicking after the end of the text. + if (Math.abs(e.clientX - this._downX) > 4 || Math.abs(e.clientY - this._downY) > 4) { + this._forceDownNode = undefined; + return; + } + if (!this._forceUncollapse || (this._editorView!.root as any).getSelection().isCollapsed) { // this is a hack to allow the cursor to be placed at the end of a document when the document ends in an inline dash comment. Apparently Chrome on Windows has a bug/feature which breaks this when clicking after the end of the text. const pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY }); const node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos); // get what prosemirror thinks the clicked node is (if it's null, then we didn't click on any text) if (pcords && node?.type === this._editorView!.state.schema.nodes.dashComment) { @@ -1125,6 +1166,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (e.clientY > lastNode?.getBoundingClientRect().bottom) { // if we clicked below the last prosemirror div, then set the selection to be the end of the document this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, this._editorView!.state.doc.content.size))); } + } else if ([this._editorView!.state.schema.nodes.ordered_list, this._editorView!.state.schema.nodes.listItem].includes(node?.type) && + node !== (this._editorView!.state.selection as NodeSelection)?.node && pcords) { + this._editorView!.dispatch(this._editorView!.state.tr.setSelection(NodeSelection.create(this._editorView!.state.doc, pcords.pos!))); } } if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); return; } @@ -1132,12 +1176,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (this.props.isSelected(true)) { // if text box is selected, then it consumes all click events e.stopPropagation(); - this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false); + this.hitBulletTargets(e.clientX, e.clientY, !this._editorView?.state.selection.empty || this._forceUncollapse, false, this._forceDownNode, e.shiftKey); } + this._forceUncollapse = !(this._editorView!.root as any).getSelection().isCollapsed; + this._forceDownNode = (this._editorView!.state.selection as NodeSelection)?.node; } // this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them. - hitBulletTargets(x: number, y: number, collapse: boolean, highlightOnly: boolean) { + hitBulletTargets(x: number, y: number, collapse: boolean, highlightOnly: boolean, downNode: Node | undefined = undefined, selectOrderedList: boolean = false) { + this._forceUncollapse = false; clearStyleSheetRules(FormattedTextBox._bulletStyleSheet); const clickPos = this._editorView!.posAtCoords({ left: x, top: y }); let olistPos = clickPos?.pos; @@ -1153,20 +1200,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp $olistPos = this._editorView?.state.doc.resolve(($olistPos as any).path[($olistPos as any).path.length - 4]); } } + const listPos = this._editorView?.state.doc.resolve(clickPos.pos); const listNode = this._editorView?.state.doc.nodeAt(clickPos.pos); - if (olistNode && olistNode.type === this._editorView?.state.schema.nodes.ordered_list) { - if (!collapse) { - if (!highlightOnly) { - this._editorView.dispatch(this._editorView.state.tr.setSelection(new NodeSelection($olistPos!))); - } - addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); - } else if (listNode && listNode.type === this._editorView.state.schema.nodes.list_item) { - if (!highlightOnly) { + if (olistNode && olistNode.type === this._editorView?.state.schema.nodes.ordered_list && listNode) { + if (!highlightOnly) { + if (selectOrderedList || (!collapse && listNode.attrs.visibility)) { + this._editorView.dispatch(this._editorView.state.tr.setSelection(new NodeSelection(selectOrderedList ? $olistPos! : listPos!))); + } else if (!listNode.attrs.visibility || downNode === listNode) { this._editorView.dispatch(this._editorView.state.tr.setNodeMarkup(clickPos.pos, listNode.type, { ...listNode.attrs, visibility: !listNode.attrs.visibility })); this._editorView.dispatch(this._editorView.state.tr.setSelection(TextSelection.create(this._editorView.state.doc, clickPos.pos))); } - addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); } + addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); } } } @@ -1347,6 +1392,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } })} + onDoubleClick={this.onDoubleClick} > <div className={`formattedTextBox-outer`} ref={this._scrollRef} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: !this.props.isSelected() ? "none" : undefined }} @@ -1393,7 +1439,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp setTimeout(() => this._editorView!.focus(), 500); e.stopPropagation(); }} > - <FontAwesomeIcon className="formattedTExtBox-audioFont" + <FontAwesomeIcon className="formattedTextBox-audioFont" style={{ color: this._recording ? "red" : "blue", opacity: this._recording ? 1 : 0.5, display: this.props.isSelected() ? "" : "none" }} icon={"microphone"} size="sm" /> </div>} </div> diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.scss b/src/client/views/nodes/formattedText/FormattedTextBoxComment.scss index 2dd63ec21..9089e7039 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.scss @@ -8,10 +8,12 @@ margin-bottom: 7px; -webkit-transform: translateX(-50%); transform: translateX(-50%); - } - .FormattedTextBox-tooltip:before { +} + +.FormattedTextBox-tooltip:before { content: ""; - height: 0; width: 0; + height: 0; + width: 0; position: absolute; left: 50%; margin-left: -5px; @@ -19,10 +21,12 @@ border: 5px solid transparent; border-bottom-width: 0; border-top-color: silver; - } - .FormattedTextBox-tooltip:after { +} + +.FormattedTextBox-tooltip:after { content: ""; - height: 0; width: 0; + height: 0; + width: 0; position: absolute; left: 50%; margin-left: -5px; @@ -30,4 +34,72 @@ border: 5px solid transparent; border-bottom-width: 0; border-top-color: white; - }
\ No newline at end of file +} + +.FormattedTextBoxComment-buttons { + display: none; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + + .FormattedTextBoxComment-button { + width: 20px; + height: 20px; + margin: 0; + margin-right: 6px; + border-radius: 50%; + pointer-events: auto; + background-color: rgb(38, 40, 41); + color: rgb(178, 181, 184); + font-size: 65%; + transition: transform 0.2s; + text-align: center; + position: relative; + + // margin-top: "auto"; + // margin-bottom: "auto"; + // background: black; + // color: white; + // display: inline-block; + // border-radius: 18px; + // font-size: 12.5px; + // width: 18px; + // height: 18px; + // margin-top: auto; + // margin-bottom: auto; + // margin-right: 3px; + // cursor: pointer; + // transition: transform 0.2s; + + .FormattedTextBoxComment-fa-icon { + margin-top: "auto"; + margin-bottom: "auto"; + background: black; + color: white; + display: inline-block; + border-radius: 18px; + font-size: 12.5px; + width: 18px; + height: 18px; + margin-top: auto; + margin-bottom: auto; + margin-right: 3px; + cursor: pointer; + transition: transform 0.2s; + // position: absolute; + // top: 50%; + // left: 50%; + // transform: translate(-50%, -50%); + } + + &:last-child { + margin-right: 0; + } + + &:hover { + background: rgb(53, 146, 199); + ; + } + } +}
\ No newline at end of file diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 4c90b6afd..56826e5c7 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -2,7 +2,7 @@ import { Mark, ResolvedPos } from "prosemirror-model"; import { EditorState, Plugin } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; -import { Doc, DocCastAsync } from "../../../../fields/Doc"; +import { Doc, DocCastAsync, Opt } from "../../../../fields/Doc"; import { Cast, FieldValue, NumCast } from "../../../../fields/Types"; import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath, returnZero, returnOne, returnEmptyFilter } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; @@ -16,6 +16,11 @@ import React = require("react"); import { Docs } from "../../../documents/Documents"; import wiki from "wikijs"; import { DocumentType } from "../../../documents/DocumentTypes"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action } from "mobx"; +import { LinkManager } from "../../../util/LinkManager"; +import { LinkDocPreview } from "../LinkDocPreview"; +import { DocumentLinksButton } from "../DocumentLinksButton"; export let formattedTextBoxCommentPlugin = new Plugin({ view(editorView) { return new FormattedTextBoxComment(editorView); } @@ -62,6 +67,10 @@ export class FormattedTextBoxComment { static mark: Mark; static textBox: FormattedTextBox | undefined; static linkDoc: Doc | undefined; + + static _deleteRef: Opt<HTMLDivElement | null>; + static _followRef: Opt<HTMLDivElement | null>; + constructor(view: any) { if (!FormattedTextBoxComment.tooltip) { const root = document.getElementById("root"); @@ -75,8 +84,8 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.tooltip.appendChild(FormattedTextBoxComment.tooltipText); FormattedTextBoxComment.tooltip.className = "FormattedTextBox-tooltip"; FormattedTextBoxComment.tooltip.style.pointerEvents = "all"; - FormattedTextBoxComment.tooltip.style.maxWidth = "350px"; - FormattedTextBoxComment.tooltip.style.maxHeight = "250px"; + FormattedTextBoxComment.tooltip.style.maxWidth = "200px"; + FormattedTextBoxComment.tooltip.style.maxHeight = "206px"; FormattedTextBoxComment.tooltip.style.width = "100%"; FormattedTextBoxComment.tooltip.style.height = "100%"; FormattedTextBoxComment.tooltip.style.overflow = "hidden"; @@ -87,12 +96,25 @@ export class FormattedTextBoxComment { const textBox = FormattedTextBoxComment.textBox; if (FormattedTextBoxComment.linkDoc && !keep && textBox) { if (FormattedTextBoxComment.linkDoc.author) { - if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { - textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight"); + + if (FormattedTextBoxComment._deleteRef && FormattedTextBoxComment._deleteRef.contains(e.target as any)) { + this.deleteLink(); + } else if (FormattedTextBoxComment._followRef && FormattedTextBoxComment._followRef.contains(e.target as any)) { + if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { + textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight"); + } else { + DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, + (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); + } } else { - DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, - (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); + if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { + textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight"); + } else { + DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, + (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); + } } + } } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) { textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400, UseCors: true }), "onRight"); @@ -106,6 +128,15 @@ export class FormattedTextBoxComment { } } + @action + deleteLink = () => { + FormattedTextBoxComment.linkDoc ? LinkManager.Instance.deleteLink(FormattedTextBoxComment.linkDoc) : null; + LinkDocPreview.LinkInfo = undefined; + DocumentLinksButton.EditLink = undefined; + //FormattedTextBoxComment.tooltipText = undefined; + FormattedTextBoxComment.Hide(); + } + public static Hide() { FormattedTextBoxComment.textBox = undefined; FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none"); @@ -210,32 +241,87 @@ export class FormattedTextBoxComment { } if (target?.author) { FormattedTextBoxComment.showCommentbox("", view, nbef); - ReactDOM.render(<ContentFittingDocumentView - Document={target} - LibraryPath={emptyPath} - fitToBox={true} - moveDocument={returnFalse} - rootSelected={returnFalse} - ScreenToLocalTransform={Transform.Identity} - parentActive={returnFalse} - addDocument={returnFalse} - removeDocument={returnFalse} - addDocTab={returnFalse} - pinToPres={returnFalse} - dontRegisterView={true} - docFilters={returnEmptyFilter} - ContainingCollectionDoc={undefined} - ContainingCollectionView={undefined} - renderDepth={0} - PanelWidth={() => Math.min(350, NumCast(target._width, 350))} - PanelHeight={() => Math.min(250, NumCast(target._height, 250))} - focus={emptyFunction} - whenActiveChanged={returnFalse} - bringToFront={returnFalse} - ContentScaling={returnOne} - NativeWidth={returnZero} - NativeHeight={returnZero} - />, FormattedTextBoxComment.tooltipText); + const docPreview = <div style={{ backgroundColor: "white", border: "8px solid white" }}> + {target.title} + <div className="wrapper" style={{ float: "right" }}> + <div title="Delete link" className="FormattedTextBoxComment-button" style={{ + display: "inline", + paddingLeft: "6px", + paddingRight: "6px", + paddingTop: "2.5px", + paddingBottom: "2.5px", + width: "20px", + height: "20px", + margin: 0, + marginRight: "6px", + borderRadius: "50%", + pointerEvents: "auto", + backgroundColor: "rgb(38, 40, 41)", + color: "rgb(178, 181, 184)", + transition: "transform 0.2s", + textAlign: "center", + position: "relative" + }} ref={(r) => this._deleteRef = r}> + <FontAwesomeIcon className="FormattedTextBox-fa-icon" icon="trash" + size="sm" /></div> + <div title="Follow link" className="FormattedTextBoxComment-button" style={{ + display: "inline", + paddingLeft: "6px", + paddingRight: "6px", + paddingTop: "2.5px", + paddingBottom: "2.5px", + width: "20px", + height: "20px", + margin: 0, + marginRight: "6px", + borderRadius: "50%", + pointerEvents: "auto", + backgroundColor: "rgb(38, 40, 41)", + color: "rgb(178, 181, 184)", + transition: "transform 0.2s", + textAlign: "center", + position: "relative" + }} ref={(r) => this._followRef = r}> + <FontAwesomeIcon className="FormattedTextBox-fa-icon" icon="arrow-right" + size="sm" /> + </div> + </div> + <div className="wrapper" style={{ + maxWidth: "180px", maxHeight: "168px", overflow: "hidden", + overflowY: "hidden", paddingTop: "5px" + }}> + <ContentFittingDocumentView + Document={target} + LibraryPath={emptyPath} + fitToBox={true} + moveDocument={returnFalse} + rootSelected={returnFalse} + ScreenToLocalTransform={Transform.Identity} + parentActive={returnFalse} + addDocument={returnFalse} + removeDocument={returnFalse} + addDocTab={returnFalse} + pinToPres={returnFalse} + dontRegisterView={true} + docFilters={returnEmptyFilter} + ContainingCollectionDoc={undefined} + ContainingCollectionView={undefined} + renderDepth={0} + PanelWidth={() => Math.min(350, NumCast(target._width, 350))} + PanelHeight={() => Math.min(250, NumCast(target._height, 250))} + focus={emptyFunction} + whenActiveChanged={returnFalse} + bringToFront={returnFalse} + ContentScaling={returnOne} + NativeWidth={returnZero} + NativeHeight={returnZero} + /> + </div> + </div>; + FormattedTextBoxComment.showCommentbox("", view, nbef); + + ReactDOM.render(docPreview, FormattedTextBoxComment.tooltipText); + FormattedTextBoxComment.tooltip.style.width = NumCast(target._width) ? `${NumCast(target._width)}` : "100%"; FormattedTextBoxComment.tooltip.style.height = NumCast(target._height) ? `${NumCast(target._height)}` : "100%"; } @@ -249,4 +335,4 @@ export class FormattedTextBoxComment { } destroy() { } -} +}
\ No newline at end of file diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index 9d69f4be7..3f73ec436 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -16,13 +16,17 @@ const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : export type KeyMap = { [key: string]: any }; -export let updateBullets = (tx2: Transaction, schema: Schema, mapStyle?: string, from?: number, to?: number) => { +export let updateBullets = (tx2: Transaction, schema: Schema, assignedMapStyle?: string, from?: number, to?: number) => { + let mapStyle = assignedMapStyle; tx2.doc.descendants((node: any, offset: any, index: any) => { if ((from === undefined || to === undefined || (from <= offset + node.nodeSize && to >= offset)) && (node.type === schema.nodes.ordered_list || node.type === schema.nodes.list_item)) { const path = (tx2.doc.resolve(offset) as any).path; let depth = Array.from(path).reduce((p: number, c: any) => p + (c.hasOwnProperty("type") && c.type === schema.nodes.ordered_list ? 1 : 0), 0); - if (node.type === schema.nodes.ordered_list) depth++; - tx2.setNodeMarkup(offset, node.type, { ...node.attrs, mapStyle: mapStyle || node.attrs.mapStyle, bulletStyle: depth, }, node.marks); + if (node.type === schema.nodes.ordered_list) { + if (depth === 0 && !assignedMapStyle) mapStyle = node.attrs.mapStyle; + depth++; + } + tx2.setNodeMarkup(offset, node.type, { ...node.attrs, mapStyle, bulletStyle: depth, }, node.marks); } }); return tx2; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 95d6c9fac..9075a6486 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -55,6 +55,7 @@ export default class RichTextMenu extends AntimodeMenu { @observable private activeFontSize: string = ""; @observable private activeFontFamily: string = ""; @observable private activeListType: string = ""; + @observable private activeAlignment: string = "left"; @observable private brushIsEmpty: boolean = true; @observable private brushMarks: Set<Mark> = new Set(); @@ -91,7 +92,7 @@ export default class RichTextMenu extends AntimodeMenu { { mark: schema.marks.pFontSize.create({ fontSize: 32 }), title: "Set font size", label: "32pt", command: this.changeFontSize }, { mark: schema.marks.pFontSize.create({ fontSize: 48 }), title: "Set font size", label: "48pt", command: this.changeFontSize }, { mark: schema.marks.pFontSize.create({ fontSize: 72 }), title: "Set font size", label: "72pt", command: this.changeFontSize }, - { mark: null, title: "", label: "various", command: unimplementedFunction, hidden: true }, + { mark: null, title: "", label: "...", command: unimplementedFunction, hidden: true }, { mark: null, title: "", label: "13pt", command: unimplementedFunction, hidden: true }, // this is here because the default size is 13, but there is no actual 13pt option ]; @@ -110,7 +111,7 @@ export default class RichTextMenu extends AntimodeMenu { this.listTypeOptions = [ { node: schema.nodes.ordered_list.create({ mapStyle: "bullet" }), title: "Set list type", label: ":", command: this.changeListType }, { node: schema.nodes.ordered_list.create({ mapStyle: "decimal" }), title: "Set list type", label: "1.1", command: this.changeListType }, - { node: schema.nodes.ordered_list.create({ mapStyle: "multi" }), title: "Set list type", label: "1.A", command: this.changeListType }, + { node: schema.nodes.ordered_list.create({ mapStyle: "multi" }), title: "Set list type", label: "A.1", command: this.changeListType }, //{ node: undefined, title: "Set list type", label: "Remove", command: this.changeListType }, ]; @@ -178,11 +179,13 @@ export default class RichTextMenu extends AntimodeMenu { // update active font family and size const active = this.getActiveFontStylesOnSelection(); - const activeFamilies = active?.get("families"); - const activeSizes = active?.get("sizes"); + const activeFamilies = active.activeFamilies; + const activeSizes = active.activeSizes; - this.activeFontFamily = !activeFamilies?.length ? "Arial" : activeFamilies.length === 1 ? String(activeFamilies[0]) : "various"; - this.activeFontSize = !activeSizes?.length ? "13pt" : activeSizes.length === 1 ? String(activeSizes[0]) : "various"; + this.activeListType = this.getActiveListStyle(); + this.activeAlignment = this.getActiveAlignment(); + this.activeFontFamily = !activeFamilies.length ? "Arial" : activeFamilies.length === 1 ? String(activeFamilies[0]) : "various"; + this.activeFontSize = !activeSizes.length ? "13pt" : activeSizes.length === 1 ? String(activeSizes[0]) : "..."; // update link in current selection const targetTitle = await this.getTextLinkTargetTitle(); @@ -213,8 +216,34 @@ export default class RichTextMenu extends AntimodeMenu { } // finds font sizes and families in selection + getActiveAlignment() { + if (this.view) { + const path = (this.view.state.selection.$from as any).path; + for (let i = path.length - 3; i < path.length; i -= 3) { + if (path[i]?.type === this.view.state.schema.nodes.paragraph) { + return path[i].attrs.align || "left"; + } + } + } + return "left"; + } + + // finds font sizes and families in selection + getActiveListStyle() { + if (this.view) { + const path = (this.view.state.selection.$from as any).path; + for (let i = 0; i < path.length; i += 3) { + if (path[i].type === this.view.state.schema.nodes.ordered_list) { + return path[i].attrs.mapStyle; + } + } + } + return "decimal"; + } + + // finds font sizes and families in selection getActiveFontStylesOnSelection() { - if (!this.view) return; + if (!this.view) return { activeFamilies: [], activeSizes: [] }; const activeFamilies: string[] = []; const activeSizes: string[] = []; @@ -228,10 +257,7 @@ export default class RichTextMenu extends AntimodeMenu { }); } - const styles = new Map<String, String[]>(); - styles.set("families", activeFamilies); - styles.set("sizes", activeSizes); - return styles; + return { activeFamilies, activeSizes }; } getMarksInSelection(state: EditorState<any>) { @@ -354,7 +380,8 @@ export default class RichTextMenu extends AntimodeMenu { return <select onChange={onChange} key={key}>{items}</select>; } - createNodesDropdown(activeOption: string, options: { node: NodeType | any | null, title: string, label: string, command: (node: NodeType | any) => void, hidden?: boolean, style?: {} }[], key: string): JSX.Element { + createNodesDropdown(activeMap: string, options: { node: NodeType | any | null, title: string, label: string, command: (node: NodeType | any) => void, hidden?: boolean, style?: {} }[], key: string): JSX.Element { + const activeOption = activeMap === "bullet" ? ":" : activeMap === "decimal" ? "1.1" : "A.1"; const items = options.map(({ title, label, hidden, style }) => { if (hidden) { return label === activeOption ? @@ -871,9 +898,9 @@ export default class RichTextMenu extends AntimodeMenu { this.createLinkButton(), this.createBrushButton(), <div className="richTextMenu-divider" />, - this.createButton("align-left", "Align Left", undefined, this.alignLeft), - this.createButton("align-center", "Align Center", undefined, this.alignCenter), - this.createButton("align-right", "Align Right", undefined, this.alignRight), + this.createButton("align-left", "Align Left", this.activeAlignment === "left", this.alignLeft), + this.createButton("align-center", "Align Center", this.activeAlignment === "center", this.alignCenter), + this.createButton("align-right", "Align Right", this.activeAlignment === "right", this.alignRight), this.createButton("indent", "Inset More", undefined, this.insetParagraph), this.createButton("outdent", "Inset Less", undefined, this.outsetParagraph), this.createButton("hand-point-left", "Hanging Indent", undefined, this.hangingIndentParagraph), diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts index f83cff9b9..1af821738 100644 --- a/src/client/views/nodes/formattedText/nodes_rts.ts +++ b/src/client/views/nodes/formattedText/nodes_rts.ts @@ -310,9 +310,9 @@ export const nodes: { [index: string]: NodeSpec } = { }], toDOM(node: any) { const map = node.attrs.bulletStyle ? node.attrs.mapStyle + node.attrs.bulletStyle : ""; - return node.attrs.visibility ? - ["li", { class: `${map}`, "data-mapStyle": node.attrs.mapStyle, "data-bulletStyle": node.attrs.bulletStyle }, 0] : - ["li", { class: `${map}`, "data-mapStyle": node.attrs.mapStyle, "data-bulletStyle": node.attrs.bulletStyle }, `${node.firstChild?.textContent}...`]; + return ["li", { class: `${map}`, "data-mapStyle": node.attrs.mapStyle, "data-bulletStyle": node.attrs.bulletStyle }, node.attrs.visibility ? 0 : + ["span", { style: `position: relative; width: 100%; height: 1.5em; overflow: hidden; display: ${node.attrs.mapStyle !== "bullet" ? "inline-block" : "list-item"}; text-overflow: ellipsis; white-space: pre` }, + `${node.firstChild?.textContent}...`]]; } }, };
\ No newline at end of file diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index c12d84bde..bbc9d388a 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -832,12 +832,14 @@ export namespace Doc { })(doc); } export function BrushDoc(doc: Doc) { + if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return doc; brushManager.BrushedDoc.set(doc, true); brushManager.BrushedDoc.set(Doc.GetProto(doc), true); return doc; } export function UnBrushDoc(doc: Doc) { + if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return doc; brushManager.BrushedDoc.delete(doc); brushManager.BrushedDoc.delete(Doc.GetProto(doc)); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 47768fd09..fafa94a11 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -6,7 +6,8 @@ import { faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, - faThumbtack, faTree, faTv, faBook, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft + faThumbtack, faTree, faTv, faBook, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft, + faAlignRight, faAlignLeft } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, reaction, trace, runInAction } from 'mobx'; @@ -35,13 +36,16 @@ import { AudioUpload } from "./AudioUpload"; import { Cast, FieldValue } from '../fields/Types'; import RichTextMenu from "../client/views/nodes/formattedText/RichTextMenu"; import { AudioBox } from "../client/views/nodes/AudioBox"; +import { CollectionViewType } from "../client/views/collections/CollectionView"; +import { DocumentType } from "../client/documents/DocumentTypes"; library.add(faTasks, faReply, faQuoteLeft, faHandPointLeft, faFolderOpen, faAngleDoubleLeft, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, faTerminal, faToggleOn, fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, - faThumbtack, faTree, faTv, faUndoAlt, faBook, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft); + faThumbtack, faTree, faTv, faUndoAlt, faBook, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft, + faAlignLeft, faAlignRight); @observer export class MobileInterface extends React.Component { @@ -423,7 +427,7 @@ export class MobileInterface extends React.Component { // The static ink menu that appears at the top @computed get inkMenu() { - return this._activeDoc._viewType !== "docking" || !this._ink ? (null) : + return this._activeDoc._viewType !== CollectionViewType.Docking || !this._ink ? (null) : <div className="colorSelector"> <InkOptionsMenu /> </div>; @@ -467,7 +471,7 @@ export class MobileInterface extends React.Component { // DocButton for switching into ink mode @computed get drawInk() { - return !this.mainContainer || this._activeDoc._viewType !== "docking" ? (null) : + return !this.mainContainer || this._activeDoc._viewType !== CollectionViewType.Docking ? (null) : <div className="docButton" id="inkButton" title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"} @@ -478,7 +482,7 @@ export class MobileInterface extends React.Component { // DocButton: Button that appears on the bottom of the screen to initiate image upload @computed get uploadImageButton() { - if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && this._activeDoc._viewType !== "docking" && this._activeDoc.title !== "WORKSPACES") { + if (this._activeDoc.type === DocumentType.COL && this._activeDoc !== this._homeDoc && this._activeDoc._viewType !== CollectionViewType.Docking && this._activeDoc.title !== "WORKSPACES") { return <div className="docButton" id="imageButton" title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"} @@ -605,9 +609,11 @@ export class MobileInterface extends React.Component { return <Uploader Document={doc} />; } - // Radial menu can only be used if it is a colleciton and it is not a homeDoc + // Radial menu can only be used if it is a colleciton and it is not a homeDoc + // (and cannot be used on Workspace to avoid pin to presentation opening on right) @computed get displayRadialMenu() { - return this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc ? <RadialMenu /> : (null); + return this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && + this._activeDoc._viewType !== CollectionViewType.Docking ? <RadialMenu /> : (null); } onDragOver = (e: React.DragEvent) => { |