diff options
author | yipstanley <stanley_yip@brown.edu> | 2019-03-17 19:27:48 -0400 |
---|---|---|
committer | yipstanley <stanley_yip@brown.edu> | 2019-03-17 19:27:48 -0400 |
commit | 65d67baa79c7d1c22db23b4ea722403d5067176b (patch) | |
tree | 2bccce4ca89dce2329d791486b3173d79c4390ff | |
parent | 94baa241afd3a99b233ae6197b7e404951347413 (diff) | |
parent | 641656b5e803305971006c386db2f465da0373ac (diff) |
changes
-rw-r--r-- | deploy/index.html | 2 | ||||
-rw-r--r-- | package-lock.json | 359 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/client/Server.ts | 32 | ||||
-rw-r--r-- | src/client/SocketStub.ts | 1 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 15 | ||||
-rw-r--r-- | src/client/util/RichTextRules.ts | 43 | ||||
-rw-r--r-- | src/client/util/RichTextSchema.tsx | 23 | ||||
-rw-r--r-- | src/client/util/TooltipTextMenu.tsx | 36 | ||||
-rw-r--r-- | src/client/views/Main.tsx | 60 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/collections/CollectionViewBase.tsx | 10 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 47 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 4 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValueBox.scss | 70 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValueBox.tsx | 69 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValuePair.tsx | 31 | ||||
-rw-r--r-- | src/fields/KeyStore.ts | 3 | ||||
-rw-r--r-- | src/mobile/ImageUpload.tsx | 36 | ||||
-rw-r--r-- | src/server/index.ts | 4 |
21 files changed, 707 insertions, 152 deletions
diff --git a/deploy/index.html b/deploy/index.html index 130da1cb9..acb085214 100644 --- a/deploy/index.html +++ b/deploy/index.html @@ -7,7 +7,7 @@ <body> <div id="root"></div> - <script src="./bundle.js"></script> + <script src="/bundle.js"></script> </body> </html>
\ No newline at end of file diff --git a/package-lock.json b/package-lock.json index da562298b..bf9741d15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -227,7 +227,7 @@ "@types/chai": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", - "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", + "integrity": "sha1-G44zthqMCcvh+FEzBxuqDb+fpxo=", "dev": true }, "@types/connect": { @@ -439,6 +439,15 @@ "@types/prosemirror-state": "*" } }, + "@types/prosemirror-inputrules": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/prosemirror-inputrules/-/prosemirror-inputrules-1.0.2.tgz", + "integrity": "sha512-bKFneQUPnkZmzCJ1uoitpKH6PFW0hc4q55NsC7mFUCvX0eZl0GRKxyfV47jkJbsbyUQoO/QFv0WwLDz2bo15sA==", + "requires": { + "@types/prosemirror-model": "*", + "@types/prosemirror-state": "*" + } + }, "@types/prosemirror-keymap": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/prosemirror-keymap/-/prosemirror-keymap-1.0.1.tgz", @@ -628,7 +637,7 @@ "@types/uuid": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz", - "integrity": "sha512-tPIgT0GUmdJQNSHxp0X2jnpQfBSTfGxUMc/2CXBU2mnyTFVYVa2ojpoQ74w0U2yn2vw3jnC640+77lkFFpdVDw==", + "integrity": "sha1-evaTYPpl7w3stB/RUL9MpcDO/fU=", "requires": { "@types/node": "*" } @@ -1138,7 +1147,7 @@ }, "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -1204,7 +1213,7 @@ "awesome-typescript-loader": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/awesome-typescript-loader/-/awesome-typescript-loader-5.2.1.tgz", - "integrity": "sha512-slv66OAJB8orL+UUaTI3pKlLorwIvS4ARZzYR9iJJyGsEgOqueMfOMdKySWzZ73vIkEe3fcwFgsKMg4d8zyb1g==", + "integrity": "sha1-pB2veEdRX0klzbqjB11h8onpE/w=", "dev": true, "requires": { "chalk": "^2.4.1", @@ -1655,7 +1664,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -1692,7 +1701,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -1731,7 +1740,7 @@ }, "buffer": { "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { @@ -1852,7 +1861,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "requires": { "camelcase": "^2.0.0", @@ -1888,7 +1897,7 @@ "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "integrity": "sha1-dgqnLPION5XoSxKHfODoNzeqKeU=", "dev": true, "requires": { "assertion-error": "^1.1.0", @@ -2282,7 +2291,7 @@ }, "content-disposition": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "resolved": "http://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" }, "content-type": { @@ -2330,7 +2339,7 @@ "copy-webpack-plugin": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz", - "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==", + "integrity": "sha1-5/QN2KaEd9QF3Rt6hUquMksVi64=", "dev": true, "requires": { "cacache": "^10.0.4", @@ -2401,7 +2410,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -2414,7 +2423,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -2540,7 +2549,7 @@ }, "d": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { @@ -2763,7 +2772,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { @@ -3306,7 +3315,7 @@ "dependencies": { "array-flatten": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "statuses": { @@ -3500,7 +3509,7 @@ }, "finalhandler": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "requires": { "debug": "2.6.9", @@ -3735,12 +3744,14 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "optional": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3760,7 +3771,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "optional": true }, "console-control-strings": { "version": "1.1.0", @@ -3882,7 +3894,8 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "optional": true }, "ini": { "version": "1.3.5", @@ -3908,6 +3921,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4489,6 +4503,21 @@ "ansi-regex": "^2.0.0" } }, + "has-binary": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", + "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", @@ -4644,7 +4673,7 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { "depd": "~1.1.2", @@ -4947,7 +4976,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { "kind-of": "^3.0.2" @@ -4991,7 +5020,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { "kind-of": "^3.0.2" @@ -5287,8 +5316,7 @@ "json3": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", - "dev": true + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" }, "json5": { "version": "1.0.1", @@ -5470,7 +5498,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { "graceful-fs": "^4.1.2", @@ -5771,7 +5799,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { @@ -5803,7 +5831,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "requires": { "camelcase-keys": "^2.0.0", @@ -5969,7 +5997,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -5995,7 +6023,7 @@ "mobx-react": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.4.3.tgz", - "integrity": "sha512-WC8yFlwvJ91hy8j6CrydAuFteUafcuvdITFQeHl3LRIf5ayfT/4W3M/byhEYD2BcJWejeXr8y4Rh2H26RunCRQ==", + "integrity": "sha1-Zwm33YlnDEDpgVkUrCyknMAr+0c=", "requires": { "hoist-non-react-statics": "^3.0.0", "react-lifecycles-compat": "^3.0.2" @@ -6009,7 +6037,7 @@ "mocha": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "integrity": "sha1-bYrlCPWRZ/lA8rWzxKYSrlDJCuY=", "dev": true, "requires": { "browser-stdout": "1.3.1", @@ -6028,7 +6056,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", "dev": true, "requires": { "ms": "2.0.0" @@ -6037,7 +6065,7 @@ "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -6057,7 +6085,7 @@ "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -6252,7 +6280,7 @@ }, "next-tick": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, @@ -6311,7 +6339,7 @@ }, "semver": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" }, "tar": { @@ -6360,7 +6388,7 @@ "node-sass": { "version": "4.11.0", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz", - "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==", + "integrity": "sha1-GD+uw5jpy+k7pDNi4naMqYimNpo=", "requires": { "async-foreach": "^0.1.3", "chalk": "^1.1.1", @@ -9672,6 +9700,11 @@ "is-wsl": "^1.1.0" } }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + }, "orderedmap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-1.0.0.tgz", @@ -9694,12 +9727,12 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "osenv": { @@ -9815,6 +9848,14 @@ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "dev": true }, + "parsejson": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", + "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", + "requires": { + "better-assert": "~1.0.0" + } + }, "parseqs": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", @@ -9865,7 +9906,7 @@ }, "path-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", "dev": true }, @@ -9884,7 +9925,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { @@ -10897,7 +10938,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -11158,7 +11199,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -11192,7 +11233,7 @@ "sass-loader": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", - "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", + "integrity": "sha1-Fv1ROMuLQkv4p1lSihly1yqtBp0=", "dev": true, "requires": { "clone-deep": "^2.0.1", @@ -11380,7 +11421,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -11632,6 +11673,204 @@ } } }, + "socketio": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/socketio/-/socketio-1.0.0.tgz", + "integrity": "sha1-aOoVmP0kBWFgFxLldJl2ftjrqMo=", + "requires": { + "express": "^4.13.3", + "socket.io": "^1.3.7" + }, + "dependencies": { + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "requires": { + "mime-types": "~2.1.11", + "negotiator": "0.6.1" + } + }, + "arraybuffer.slice": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=" + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "component-emitter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=" + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "requires": { + "ms": "0.7.2" + } + }, + "engine.io": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.5.tgz", + "integrity": "sha512-j1DWIcktw4hRwrv6nWx++5nFH2X64x16MAG2P0Lmi5Dvdfi3I+Jhc7JKJIdAmDJa+5aZ/imHV7dWRPy2Cqjh3A==", + "requires": { + "accepts": "1.3.3", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "ws": "~1.1.5" + } + }, + "engine.io-client": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.5.tgz", + "integrity": "sha512-AYTgHyeVUPitsseqjoedjhYJapNVoSPShbZ+tEUX9/73jgZ/Z3sUlJf9oYgdEBBdVhupUpUqSxH0kBCXlQnmZg==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parsejson": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~1.1.5", + "xmlhttprequest-ssl": "1.5.3", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + } + } + }, + "engine.io-parser": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", + "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.6", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary": "0.1.7", + "wtf-8": "1.0.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + }, + "object-assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" + }, + "socket.io": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.4.tgz", + "integrity": "sha1-L37O3DORvy1cc+KR/iM+bjTU3QA=", + "requires": { + "debug": "2.3.3", + "engine.io": "~1.8.4", + "has-binary": "0.1.7", + "object-assign": "4.1.0", + "socket.io-adapter": "0.5.0", + "socket.io-client": "1.7.4", + "socket.io-parser": "2.3.1" + } + }, + "socket.io-adapter": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", + "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", + "requires": { + "debug": "2.3.3", + "socket.io-parser": "2.3.1" + } + }, + "socket.io-client": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.4.tgz", + "integrity": "sha1-7J+CA1btme9tNX8HVtZIcXvdQoE=", + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "2.3.3", + "engine.io-client": "~1.8.4", + "has-binary": "0.1.7", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseuri": "0.0.5", + "socket.io-parser": "2.3.1", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + } + } + }, + "socket.io-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", + "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", + "requires": { + "component-emitter": "1.1.2", + "debug": "2.2.0", + "isarray": "0.0.1", + "json3": "3.3.2" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + } + } + }, + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "requires": { + "options": ">=0.0.5", + "ultron": "1.0.x" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", + "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=" + } + } + }, "sockjs": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", @@ -11962,7 +12201,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -11970,7 +12209,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -11986,7 +12225,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-indent": { @@ -12005,7 +12244,7 @@ "style-loader": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", - "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "integrity": "sha1-y5FUYG8+dxq2xKtjcCahBJF02SU=", "dev": true, "requires": { "loader-utils": "^1.1.0", @@ -12401,7 +12640,7 @@ "ts-node": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", - "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "integrity": "sha1-lWLcLR5tJI0kvFX3c+P2FDN9m68=", "dev": true, "requires": { "arrify": "^1.0.0", @@ -12422,7 +12661,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -12527,6 +12766,11 @@ "random-bytes": "~1.0.0" } }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" + }, "undefsafe": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", @@ -12788,7 +13032,7 @@ "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=" }, "v8-compile-cache": { "version": "2.0.2", @@ -12827,7 +13071,7 @@ }, "vm-browserify": { "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "resolved": "http://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", "dev": true, "requires": { @@ -13368,7 +13612,7 @@ "webpack-log": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "integrity": "sha1-W3ko4GN1k/EZ0y9iJ8HgrDHhtH8=", "dev": true, "requires": { "ansi-colors": "^3.0.0", @@ -13616,7 +13860,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", @@ -13658,6 +13902,11 @@ "async-limiter": "~1.0.0" } }, + "wtf-8": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", + "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=" + }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", diff --git a/package.json b/package.json index ed593898d..f49b2e66e 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "@types/passport-local": "^1.0.33", "@types/prosemirror-commands": "^1.0.1", "@types/prosemirror-history": "^1.0.1", + "@types/prosemirror-inputrules": "^1.0.2", "@types/prosemirror-keymap": "^1.0.1", "@types/prosemirror-model": "^1.7.0", "@types/prosemirror-schema-basic": "^1.0.1", @@ -133,6 +134,7 @@ "request": "^2.88.0", "socket.io": "^2.2.0", "socket.io-client": "^2.2.0", + "socketio": "^1.0.0", "url-loader": "^1.1.2", "uuid": "^3.3.2" } diff --git a/src/client/Server.ts b/src/client/Server.ts index f0cf0bb9b..5e42c8285 100644 --- a/src/client/Server.ts +++ b/src/client/Server.ts @@ -40,8 +40,8 @@ export class Server { return this.ClientFieldsCached.get(fieldid); }, (field, reaction) => { if (field !== "<Waiting>") { - callback(field) reaction.dispose() + callback(field) } }) } @@ -49,14 +49,38 @@ export class Server { } public static GetFields(fieldIds: FieldId[], callback: (fields: { [id: string]: Field }) => any) { - SocketStub.SEND_FIELDS_REQUEST(fieldIds, (fields) => { + let neededFieldIds: FieldId[] = []; + let waitingFieldIds: FieldId[] = []; + let existingFields: { [id: string]: Field } = {}; + for (let id of fieldIds) { + let field = this.ClientFieldsCached.get(id); + if (!field) { + neededFieldIds.push(id); + } else if (field === FieldWaiting) { + waitingFieldIds.push(id); + } else { + existingFields[id] = field; + } + } + SocketStub.SEND_FIELDS_REQUEST(neededFieldIds, (fields) => { for (let key in fields) { let field = fields[key]; if (!this.ClientFieldsCached.has(field.Id)) { this.ClientFieldsCached.set(field.Id, field) } } - callback(fields) + reaction(() => { + return waitingFieldIds.map(this.ClientFieldsCached.get); + }, (cachedFields, reaction) => { + if (!cachedFields.some(field => !field || field === FieldWaiting)) { + reaction.dispose(); + for (let field of cachedFields) { + let realField = field as Field; + existingFields[realField.Id] = realField; + } + callback({ ...fields, ...existingFields }) + } + }, { fireImmediately: true }) }); } @@ -121,4 +145,4 @@ export class Server { } Server.Socket.on(MessageStore.Foo.Message, Server.connected); -Server.Socket.on(MessageStore.SetField.Message, Server.updateField);
\ No newline at end of file +Server.Socket.on(MessageStore.SetField.Message, Server.updateField); diff --git a/src/client/SocketStub.ts b/src/client/SocketStub.ts index 18df4ca0a..a0b89b7c9 100644 --- a/src/client/SocketStub.ts +++ b/src/client/SocketStub.ts @@ -7,6 +7,7 @@ import { Utils } from "../Utils"; import { Server } from "./Server"; import { ServerUtils } from "../server/ServerUtil"; +//TODO tfs: I think it might be cleaner to not have SocketStub deal with turning what the server gives it into Fields (in other words not call ServerUtils.FromJson), and leave that for the Server class. export class SocketStub { static FieldStore: ObservableMap<FieldId, Field> = new ObservableMap(); diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 05bc743be..a92cf97fe 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -175,7 +175,7 @@ export namespace Documents { return SetInstanceOptions(GetAudioPrototype(), options, [new URL(url), AudioField]); } export function TextDocument(options: DocumentOptions = {}) { - return SetInstanceOptions(GetTextPrototype(), options, ["", RichTextField]); + return SetInstanceOptions(GetTextPrototype(), options, ["", TextField]); } export function PdfDocument(url: string, options: DocumentOptions = {}) { return SetInstanceOptions(GetPdfPrototype(), options, [new URL(url), PDFField]); @@ -215,4 +215,17 @@ export namespace Documents { + FormattedTextBox.LayoutString(fieldName + "Key") + `</div> </div>` }; + + function Caption() { + return (` +<div> + <div style="margin:auto; height:85%; width:85%;"> + {layout} + </div> + <div style="height:15%; width:100%; position:absolute"> + <FormattedTextBox doc={Document} DocumentViewForField={DocumentView} bindings={bindings} fieldKey={"CaptionKey"} isSelected={isSelected} select={select} selectOnLoad={SelectOnLoad} isTopMost={isTopMost}/> + </div> +</div> + `) + } }
\ No newline at end of file diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts new file mode 100644 index 000000000..3b8396510 --- /dev/null +++ b/src/client/util/RichTextRules.ts @@ -0,0 +1,43 @@ +import { + inputRules, + wrappingInputRule, + textblockTypeInputRule, + smartQuotes, + emDash, + ellipsis +} from "prosemirror-inputrules"; +import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model"; + +import { schema } from "./RichTextSchema"; + +export const inpRules = { + rules: [ + ...smartQuotes, + ellipsis, + emDash, + + // > blockquote + wrappingInputRule(/^\s*>\s$/, schema.nodes.blockquote), + + // 1. ordered list + wrappingInputRule( + /^(\d+)\.\s$/, + schema.nodes.ordered_list, + match => ({ order: +match[1] }), + (match, node) => node.childCount + node.attrs.order === +match[1] + ), + + // * bullet list + wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.bullet_list), + + // ``` code block + textblockTypeInputRule(/^```$/, schema.nodes.code_block), + + // # heading + textblockTypeInputRule( + new RegExp("^(#{1,6})\\s$"), + schema.nodes.heading, + match => ({ level: match[1].length }) + ) + ] +}; diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index abf448c9f..2a3c1da6e 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -1,12 +1,15 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray } from "prosemirror-model" +import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model" import { joinUp, lift, setBlockType, toggleMark, wrapIn } from 'prosemirror-commands' import { redo, undo } from 'prosemirror-history' -import { orderedList, bulletList, listItem } from 'prosemirror-schema-list' +import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list' +import { EditorState, Transaction, NodeSelection, } from "prosemirror-state"; +import { EditorView, } from "prosemirror-view"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0] + // :: Object // [Specs](#model.NodeSpec) for the nodes defined in this schema. export const nodes: { [index: string]: NodeSpec } = { @@ -113,12 +116,22 @@ export const nodes: { [index: string]: NodeSpec } = { content: 'list_item+', group: 'block' }, + //this doesn't currently work for some reason bullet_list: { + ...bulletList, content: 'list_item+', group: 'block', - parseDOM: [{ tag: "ul" }, { style: "list-style-type=disc;" }], - toDOM() { return ulDOM } - }, + // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }], + // toDOM() { return ulDOM } + }, + //bullet_list: { + // content: 'list_item+', + // group: 'block', + //active: blockActive(schema.nodes.bullet_list), + //enable: wrapInList(schema.nodes.bullet_list), + //run: wrapInList(schema.nodes.bullet_list), + //select: state => true, + // }, list_item: { ...listItem, content: 'paragraph block*' diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 8cc653bf2..2a613ba8b 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -2,10 +2,10 @@ import { action, IReactionDisposer, reaction } from "mobx"; import { baseKeymap } from "prosemirror-commands"; import { history, redo, undo } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; -const { exampleSetup } = require("prosemirror-example-setup") -import { EditorState, Transaction, } from "prosemirror-state"; +import { EditorState, Transaction, NodeSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { schema } from "./RichTextSchema"; +import { Schema, NodeType } from "prosemirror-model" import React = require("react") import "./TooltipTextMenu.scss"; const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); @@ -16,7 +16,7 @@ import { } from '@fortawesome/free-solid-svg-icons'; - +//appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc. export class TooltipTextMenu { private tooltip: HTMLElement; @@ -39,7 +39,8 @@ export class TooltipTextMenu { { command: toggleMark(schema.marks.strikethrough), dom: this.icon("S", "strikethrough") }, { command: toggleMark(schema.marks.superscript), dom: this.icon("s", "superscript") }, { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript") }, - { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") } + //this doesn't work currently - look into notion of active block + { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, ] items.forEach(({ dom }) => this.tooltip.appendChild(dom)); @@ -49,7 +50,9 @@ export class TooltipTextMenu { view.focus(); items.forEach(({ command, dom }) => { if (dom.contains(e.srcElement)) { - command(view.state, view.dispatch, view) + let active = command(view.state, view.dispatch, view); + //uncomment this if we want the bullet button to disappear if current selection is bulleted + // dom.style.display = active ? "" : "none" } }) }) @@ -66,13 +69,25 @@ export class TooltipTextMenu { return span; } - blockActive(view: EditorView) { - const { $from, to } = view.state.selection + //adapted this method - use it to check if block has a tag (ie bulleting) + blockActive(type: NodeType<Schema<string, string>>, state: EditorState) { + let attrs = {}; + + if (state.selection instanceof NodeSelection) { + const sel: NodeSelection = state.selection; + let $from = sel.$from; + let to = sel.to; + let node = sel.node; + + if (node) { + return node.hasMarkup(type, attrs); + } - return to <= $from.end() && $from.parent.hasMarkup(schema.nodes.bulletList); + return to <= $from.end() && $from.parent.hasMarkup(type, attrs); + } } - //this doesn't currently work but hopefully will soon + //this doesn't currently work but could be used to use icons for buttons unorderedListIcon(): HTMLSpanElement { let span = document.createElement("span"); let icon = document.createElement("FontAwesomeIcon"); @@ -105,8 +120,6 @@ export class TooltipTextMenu { // Otherwise, reposition it and update its content this.tooltip.style.display = "" let { from, to } = state.selection - // These are in screen coordinates - //check this - tranform let start = view.coordsAtPos(from), end = view.coordsAtPos(to) // The box in which the tooltip is positioned, to use as base let box = this.tooltip.offsetParent!.getBoundingClientRect() @@ -116,6 +129,7 @@ export class TooltipTextMenu { this.tooltip.style.left = (left - box.left) + "px" let width = Math.abs(start.left - end.left) / 2; let mid = Math.min(start.left, end.left) + width; + //THIS WIDTH IS 15 * NUMBER OF ICONS + 15 this.tooltip.style.width = 122 + "px"; this.tooltip.style.bottom = (box.bottom - start.top) + "px"; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 3a68b98ce..89ef16cc9 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -1,4 +1,4 @@ -import { action, configure } from 'mobx'; +import { action, configure, observable, runInAction } from 'mobx'; import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; @@ -31,6 +31,9 @@ import { faRedoAlt } from '@fortawesome/free-solid-svg-icons'; import { faPenNib } from '@fortawesome/free-solid-svg-icons'; import { faFilm } from '@fortawesome/free-solid-svg-icons'; import { faMusic } from '@fortawesome/free-solid-svg-icons'; +import Measure from 'react-measure'; +import { Field, Opt } from '../../fields/Field'; +import { ListField } from '../../fields/ListField'; configure({ enforceActions: "observed" }); // causes errors to be generated when modifying an observable outside of an action @@ -41,11 +44,17 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) { ContextMenu.Instance.clearItems() } }), true) - -const mainDocId = "mainDoc"; -let mainContainer: Document; +const pathname = window.location.pathname.split("/"); +const mainDocId = pathname[pathname.length - 1]; +const pendingDocId = "pending-doc" +var mainContainer: Document; let mainfreeform: Document; +class mainDocFrame { + @observable public static pwidth: number = 0; + @observable public static pheight: number = 0; +} + library.add(faFont); library.add(faImage); library.add(faFilePdf); @@ -73,9 +82,24 @@ Documents.initProtos(mainDocId, (res?: Document) => { var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(mainfreeform)] }] }; mainContainer.SetText(KeyStore.Data, JSON.stringify(dockingLayout)); mainContainer.Set(KeyStore.ActiveFrame, mainfreeform); + let pendingDocument = Documents.SchemaDocument([], { title: "New Mobile Uploads" }, pendingDocId) + mainContainer.Set(KeyStore.OptionalRightCollection, pendingDocument) }, 0); } + // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) + setTimeout(() => { + Server.GetField(pendingDocId, (res?: Field) => { + if (res instanceof Document) { + res.GetTAsync<ListField<Document>>(KeyStore.Data, ListField, (f: Opt<ListField<Document>>) => { + if (f && f.Data.length > 0) { + CollectionDockingView.Instance.AddRightSplit(res) + } + }) + } + }) + }, 50) + let imgurl = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"; let pdfurl = "http://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf" let weburl = "https://cs.brown.edu/courses/cs166/"; @@ -106,16 +130,24 @@ Documents.initProtos(mainDocId, (res?: Document) => { ReactDOM.render(( <div style={{ position: "absolute", width: "100%", height: "100%" }}> {/* <div id="dash-title">— DASH —</div> */} - - <DocumentView Document={mainContainer} - AddDocument={undefined} RemoveDocument={undefined} ScreenToLocalTransform={() => Transform.Identity} - ContentScaling={() => 1} - PanelWidth={() => 0} - PanelHeight={() => 0} - isTopMost={true} - SelectOnLoad={false} - focus={() => { }} - ContainingCollectionView={undefined} /> + <Measure onResize={(r: any) => runInAction(() => { + mainDocFrame.pwidth = r.entry.width; + mainDocFrame.pheight = r.entry.height; + })}> + {({ measureRef }) => + <div ref={measureRef} style={{ position: "absolute", width: "100%", height: "100%" }}> + <DocumentView Document={mainContainer} + AddDocument={undefined} RemoveDocument={undefined} ScreenToLocalTransform={() => Transform.Identity} + ContentScaling={() => 1} + PanelWidth={() => mainDocFrame.pwidth} + PanelHeight={() => mainDocFrame.pheight} + isTopMost={true} + SelectOnLoad={false} + focus={() => { }} + ContainingCollectionView={undefined} /> + </div> + } + </Measure> <DocumentDecorations /> <ContextMenu /> <button className="clear-db-button" onClick={clearDatabase}>Clear Database</button> diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 94005a4c0..ba9e8c29f 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -212,6 +212,12 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp stack.remove(); //} })); + stack.header.controlsContainer.find('.lm_popout') //get the close icon + .off('click') //unbind the current click handler + .click(action(function () { + var url = "http://localhost:1050/doc/" + stack.contentItems[0].tab.contentItem.config.props.documentId; + let win = window.open(url, stack.contentItems[0].tab.title, "width=300,height=400"); + })); } render() { diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 5c0eab392..988c9941f 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -1,11 +1,10 @@ -import { action, computed, observable, trace } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { FieldWaiting } from "../../../fields/Field"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; import { TextField } from "../../../fields/TextField"; -import { Documents } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; @@ -198,7 +197,6 @@ export class CollectionFreeFormView extends CollectionViewBase { @action private SetPan(panX: number, panY: number) { var x1 = this.getLocalTransform().inverse().Scale; - var x2 = this.getTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / x1) * this.nativeWidth, Math.max(0, panX)); const newPanY = Math.min((1 - 1 / x1) * this.nativeHeight, Math.max(0, panY)); this.props.Document.SetNumber(KeyStore.PanX, this.isAnnotationOverlay ? newPanX : panX); @@ -316,7 +314,7 @@ export class CollectionFreeFormView extends CollectionViewBase { //when focus is lost, this will remove the preview cursor @action - onBlur = (e: React.FocusEvent<HTMLDivElement>): void => { + onBlur = (): void => { this.PreviewCursorVisible = false; } diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index eda62a4ca..d9598aa72 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -47,6 +47,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> protected drop(e: Event, de: DragManager.DropEvent) { const docView: DocumentView = de.data["documentView"]; const doc: Document = de.data["document"]; + if (docView && (!docView.props.ContainingCollectionView || docView.props.ContainingCollectionView !== this.props.CollectionView)) { if (docView.props.RemoveDocument) { docView.props.RemoveDocument(docView.props.Document); @@ -61,12 +62,17 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> @action protected onDrop(e: React.DragEvent, options: DocumentOptions): void { - e.stopPropagation() - e.preventDefault() let that = this; let html = e.dataTransfer.getData("text/html"); let text = e.dataTransfer.getData("text/plain"); + + if (text && text.startsWith("<div")) { + return; + } + e.stopPropagation() + e.preventDefault() + if (html && html.indexOf("<img") != 0) { console.log("not good"); let htmlDoc = Documents.HtmlDocument(html, { ...options, width: 300, height: 300 }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 54afda8f3..76127a7f3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -14,20 +14,21 @@ import { Transform } from "../../util/Transform"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionView, CollectionViewType } from "../collections/CollectionView"; import { ContextMenu } from "../ContextMenu"; -import {FormattedTextBox} from "../nodes/FormattedTextBox" -import {ImageBox} from "../nodes/ImageBox"; -import {CollectionFreeFormView} from "../collections/CollectionFreeFormView" -import {PDFBox} from "../nodes/PDFBox"; -import {WebBox} from "../nodes/WebBox" -import {CollectionSchemaView} from "../collections/CollectionSchemaView" -import {AudioBox} from "../nodes/AudioBox"; -import {VideoBox} from "../nodes/VideoBox"; -import {CollectionPDFView} from "../collections/CollectionPDFView" -import {CollectionVideoView} from "../collections/CollectionVideoView" -import {KeyValueBox} from "../nodes/KeyValueBox" +import { FormattedTextBox } from "../nodes/FormattedTextBox" +import { ImageBox } from "../nodes/ImageBox"; +import { CollectionFreeFormView } from "../collections/CollectionFreeFormView" +import { PDFBox } from "../nodes/PDFBox"; +import { WebBox } from "../nodes/WebBox" +import { CollectionSchemaView } from "../collections/CollectionSchemaView" +import { AudioBox } from "../nodes/AudioBox"; +import { VideoBox } from "../nodes/VideoBox"; +import { CollectionPDFView } from "../collections/CollectionPDFView" +import { CollectionVideoView } from "../collections/CollectionVideoView" +import { KeyValueBox } from "../nodes/KeyValueBox" import "./DocumentView.scss"; import React = require("react"); import { DocumentContentsView } from "./DocumentContentsView"; +import { Utils } from "../../../Utils"; import { faUserPlus } from "@fortawesome/free-solid-svg-icons"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? @@ -243,6 +244,9 @@ export class DocumentView extends React.Component<DocumentViewProps> { SelectionManager.SelectDoc(this, e.ctrlKey); } } + stopPropogation = (e: React.SyntheticEvent) => { + e.stopPropagation(); + } deleteClicked = (): void => { if (this.props.RemoveDocument) { @@ -295,6 +299,20 @@ export class DocumentView extends React.Component<DocumentViewProps> { e.stopPropagation(); } + onDrop = (e: React.DragEvent) => { + if (e.isDefaultPrevented()) { + return; + } + let text = e.dataTransfer.getData("text/plain"); + if (text && text.startsWith("<div")) { + let oldLayout = this.props.Document.GetText(KeyStore.Layout, ""); + let layout = text.replace("{layout}", oldLayout); + this.props.Document.SetText(KeyStore.Layout, layout); + e.stopPropagation(); + e.preventDefault(); + } + } + @action onContextMenu = (e: React.MouseEvent): void => { e.stopPropagation(); @@ -309,6 +327,12 @@ export class DocumentView extends React.Component<DocumentViewProps> { ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked }) ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) }) ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) }) + ContextMenu.Instance.addItem({ + description: "Copy ID", + event: () => { + Utils.CopyText(this.props.Document.Id); + } + }); //ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) }) ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15) if (!this.topMost) { @@ -351,6 +375,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { transformOrigin: "left top", transform: `scale(${scaling} , ${scaling})` }} + onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} > <DocumentContents {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={KeyStore.Layout} /> diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f5d4c030b..d7026ed67 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -14,6 +14,9 @@ import { Plugin } from 'prosemirror-state' import { Decoration, DecorationSet } from 'prosemirror-view' import { TooltipTextMenu } from "../../util/TooltipTextMenu" import { ContextMenu } from "../../views/ContextMenu"; +import { inpRules } from "../../util/RichTextRules"; +const { buildMenuItems } = require("prosemirror-example-setup"); +const { menuBar } = require("prosemirror-menu"); @@ -60,6 +63,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { let state: EditorState; const config = { schema, + inpRules, //these currently don't do anything, but could eventually be helpful plugins: [ history(), keymap({ "Mod-z": undo, "Mod-y": redo }), diff --git a/src/client/views/nodes/KeyValueBox.scss b/src/client/views/nodes/KeyValueBox.scss index e946275fa..63ae75424 100644 --- a/src/client/views/nodes/KeyValueBox.scss +++ b/src/client/views/nodes/KeyValueBox.scss @@ -1,31 +1,57 @@ +@import "../global_variables"; .keyValueBox-cont { - overflow-y: scroll; - height: 100%; - border: black; - border-width: 1px; - border-style: solid; - box-sizing: border-box; - display: inline-block; - .imageBox-cont img { - max-height: 45px; - height: auto; - } + overflow-y: scroll; + height: 100%; + background-color: $light-color; + border: 1px solid $intermediate-color; + border-radius: $border-radius; + box-sizing: border-box; + display: inline-block; + .imageBox-cont img { + max-height: 45px; + height: auto; + } + td { + padding: 6px 8px; + border-right: 1px solid $intermediate-color; + border-top: 1px solid $intermediate-color; + &:last-child { + border-right: none; + } + } } + .keyValueBox-table { - position: relative; + position: relative; + border-collapse: collapse; } + .keyValueBox-header { - background: gray; + background: $intermediate-color; + color: $light-color; + text-transform: uppercase; + letter-spacing: 2px; + font-size: 12px; + height: 30px; + padding-top: 4px; + th { + font-weight: normal; + &:first-child { + border-right: 1px solid $light-color; + } + } } + .keyValueBox-evenRow { - background: white; - .formattedTextBox-cont { - background: white; - } + background: $light-color; + .formattedTextBox-cont { + background: $light-color; + } } + .keyValueBox-oddRow { - background: lightGray; - .formattedTextBox-cont { - background: lightgray; - } -} + background: $light-color-secondary; + .formattedTextBox-cont { + background: $light-color-secondary; + } +}
\ No newline at end of file diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index ac8c949a9..283c1f732 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -2,17 +2,62 @@ import { observer } from "mobx-react"; import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app import { Document } from '../../../fields/Document'; -import { FieldWaiting } from '../../../fields/Field'; +import { FieldWaiting, Field } from '../../../fields/Field'; import { KeyStore } from '../../../fields/KeyStore'; import { FieldView, FieldViewProps } from './FieldView'; import "./KeyValueBox.scss"; import { KeyValuePair } from "./KeyValuePair"; import React = require("react") +import { CompileScript, ToField } from "../../util/Scripting"; +import { Key } from '../../../fields/Key'; +import { observable, action } from "mobx"; @observer export class KeyValueBox extends React.Component<FieldViewProps> { public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr) } + @observable private _keyInput: string = ""; + @observable private _valueInput: string = ""; + + + constructor(props: FieldViewProps) { + super(props); + } + + + + shouldComponentUpdate() { + return false; + } + + @action + onEnterKey = (e: React.KeyboardEvent): void => { + if (e.key == 'Enter') { + if (this._keyInput && this._valueInput) { + let doc = this.props.doc.GetT(KeyStore.Data, Document); + if (!doc || doc == FieldWaiting) { + return + } + let realDoc = doc; + + let script = CompileScript(this._valueInput, undefined, true); + if (!script.compiled) { + return; + } + let field = script(); + if (field instanceof Field) { + realDoc.Set(new Key(this._keyInput), field); + } else { + let dataField = ToField(field); + if (dataField) { + realDoc.Set(new Key(this._keyInput), dataField); + } + } + this._keyInput = "" + this._valueInput = "" + } + } + } onPointerDown = (e: React.PointerEvent): void => { if (e.buttons === 1 && this.props.isSelected()) { @@ -33,7 +78,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> { let ids: { [key: string]: string } = {}; let protos = doc.GetAllPrototypes(); for (const proto of protos) { - proto._proxies.forEach((val, key) => { + proto._proxies.forEach((val: any, key: string) => { if (!(key in ids)) { ids[key] = key; } @@ -48,9 +93,26 @@ export class KeyValueBox extends React.Component<FieldViewProps> { return rows; } + @action + keyChanged = (e: React.ChangeEvent<HTMLInputElement>) => { + this._keyInput = e.currentTarget.value; + } + + @action + valueChanged = (e: React.ChangeEvent<HTMLInputElement>) => { + this._valueInput = e.currentTarget.value; + } - render() { + newKeyValue = () => { + return ( + <tr> + <td><input type="text" value={this._keyInput} placeholder="Key" onChange={this.keyChanged} /></td> + <td><input type="text" value={this._valueInput} placeholder="Value" onChange={this.valueChanged} onKeyPress={this.onEnterKey} /></td> + </tr> + ) + } + render() { return (<div className="keyValueBox-cont" onWheel={this.onPointerWheel}> <table className="keyValueBox-table"> <tbody> @@ -59,6 +121,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> { <th>Fields</th> </tr> {this.createTable()} + {this.newKeyValue()} </tbody> </table> </div>) diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index a97e98313..111f85a05 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -8,6 +8,8 @@ import { observable, action } from 'mobx'; import { Document } from '../../../fields/Document'; import { Key } from '../../../fields/Key'; import { Server } from "../../Server" +import { EditableView } from "../EditableView"; +import { CompileScript, ToField } from "../../util/Scripting"; // Represents one row in a key value plane @@ -48,10 +50,37 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> { bindings: {}, selectOnLoad: false, } + let contents = ( + <FieldView {...props} /> + ); return ( <tr className={this.props.rowStyle}> <td>{this.key.Name}</td> - <td><FieldView {...props} /></td> + <td><EditableView contents={contents} height={36} GetValue={() => { + let field = props.doc.Get(props.fieldKey); + if (field && field instanceof Field) { + return field.ToScriptString(); + } + return field || ""; + }} + SetValue={(value: string) => { + let script = CompileScript(value, undefined, true); + if (!script.compiled) { + return false; + } + let field = script(); + if (field instanceof Field) { + props.doc.Set(props.fieldKey, field); + return true; + } else { + let dataField = ToField(field); + if (dataField) { + props.doc.Set(props.fieldKey, dataField); + return true; + } + } + return false; + }}></EditableView></td> </tr> ) } diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index 06cdc8fc8..9c7a45af4 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -37,4 +37,7 @@ export namespace KeyStore { export const CurPage = new Key("CurPage"); export const NumPages = new Key("NumPages"); export const Ink = new Key("Ink"); + export const OptionalRightCollection = new Key("OptionalRightCollection"); + export const Archives = new Key("Archives"); + export const Updated = new Key("Updated"); } diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 9a9ea0693..ad589d51f 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -1,4 +1,4 @@ -import * as ReactDOM from 'react-dom'; +import * as ReactDOM from 'react-dom'; import React = require('react'); import "./ImageUpload.scss" import { action, runInAction } from "mobx"; @@ -7,37 +7,37 @@ import { action, runInAction } from "mobx"; const onPointerDown = (e: React.TouchEvent) => { - let imgInput = document.getElementById("input_image_file"); - if (imgInput){ - imgInput.click(); + let imgInput = document.getElementById("input_image_file"); + if (imgInput) { + imgInput.click(); } } -const onFileLoad = (file:any) => { - let img = new Image(); +const onFileLoad = (file: any) => { + let img = new Image(); let imgPrev = document.getElementById("img_preview") - if (imgPrev){ - let files = file.target.files; - if (files.length != 0){ + if (imgPrev) { + let files = file.target.files; + if (files.length != 0) { console.log(files[0]); - console.log(window.location.origin) + console.log(window.location.origin) const upload = window.location.origin + "/upload"; - let formData = new FormData(); + let formData = new FormData(); formData.append("file", files[0]); console.log(window.location.origin + file[0]) - + //imgPrev.setAttribute("src", window.location.origin + files[0].name) } } - - + + } ReactDOM.render(( - <div className = "imgupload_cont"> - <button className = "button_file" onTouchStart = {onPointerDown}> Open Image </button> - <input type= "file" accept = "image/*" capture="camera" onChange = {onFileLoad} className = "input_file" id = "input_image_file"></input> - <img id = "img_preview" src = ""></img> + <div className="imgupload_cont"> + <button className="button_file" onTouchStart={onPointerDown}> Open Image </button> + <input type="file" accept="image/*" capture="filesystem" onChange={onFileLoad} className="input_file" id="input_image_file"></input> + <img id="img_preview" src=""></img> </div>), document.getElementById('root') );
\ No newline at end of file diff --git a/src/server/index.ts b/src/server/index.ts index 86cef77f4..0a89c61bd 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -120,6 +120,10 @@ app.get("/pull", (req, res) => { }) }); +app.get("/doc/:docId", (req, res) => { + res.sendFile(path.join(__dirname, '../../deploy/index.html')); +}) + app.get("/hello", (req, res) => { res.send("<p>Hello</p>"); }) |