aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-12-06 19:03:26 -0500
committerbobzel <zzzman@gmail.com>2023-12-06 19:03:26 -0500
commit6d38096db5f0d550866d82d954436447d0c36a65 (patch)
tree2d53b5e98716ce883f77c04622694af19b088b35
parent8d8878037c9d1aaee18b10bd744f993cb4d3e7c1 (diff)
converted equationEditor from a npm module to a local file. commented out old google-maps code.
-rw-r--r--package-lock.json362
-rw-r--r--package.json8
-rw-r--r--src/client/views/nodes/EquationBox.tsx2
-rw-r--r--src/client/views/nodes/MapBox/MapBox.tsx11
-rw-r--r--src/client/views/nodes/MapBox/MapBox2.tsx1194
-rw-r--r--src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx184
-rw-r--r--src/client/views/nodes/formattedText/EquationEditor.tsx87
-rw-r--r--src/client/views/nodes/formattedText/EquationView.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx2
9 files changed, 815 insertions, 1037 deletions
diff --git a/package-lock.json b/package-lock.json
index f02c8c678..76d33eaee 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -74,7 +74,6 @@
"D": "^1.0.0",
"d3": "^7.8.5",
"depcheck": "^1.4.7",
- "equation-editor-react": "^0.0.10",
"exif": "^0.6.0",
"exifr": "^7.1.3",
"express": "^4.18.2",
@@ -95,7 +94,6 @@
"function-plot": "^1.23.3",
"golden-layout": "^2.6.0",
"google-auth-library": "^9.4.1",
- "google-maps-react": "^2.0.6",
"googleapis": "^129.0.0",
"googlephotos": "^0.3.5",
"got": "^14.0.0",
@@ -117,6 +115,7 @@
"jszip": "^3.10.1",
"lodash": "^4.17.21",
"material-ui": "^0.20.2",
+ "mathquill": "^0.10.1-a",
"md5-file": "^5.0.0",
"memorystream": "^0.3.1",
"mobile-detect": "^1.4.5",
@@ -130,7 +129,7 @@
"nodemailer": "^6.9.7",
"nodemon": "^3.0.2",
"normalize.css": "^8.0.1",
- "npm": "^10.2.4",
+ "npm": "^10.2.5",
"openai": "^4.20.1",
"p-limit": "^5.0.0",
"passport": "^0.7.0",
@@ -143,7 +142,6 @@
"probe-image-size": "^7.2.3",
"process": "^0.11.10",
"prosemirror-commands": "^1.5.2",
- "prosemirror-dev-tools": "^4.0.0",
"prosemirror-find-replace": "^0.9.0",
"prosemirror-history": "^1.3.2",
"prosemirror-inputrules": "^1.3.0",
@@ -235,7 +233,6 @@
"@types/express-session": "^1.17.10",
"@types/express-validator": "^3.0.0",
"@types/file-saver": "^2.0.7",
- "@types/google-maps-react": "^2.0.5",
"@types/jquery": "^3.5.29",
"@types/libxmljs": "^0.18.12",
"@types/lodash": "^4.14.202",
@@ -250,7 +247,6 @@
"@types/passport-local": "^1.0.38",
"@types/pdfjs-dist": "^2.10.378",
"@types/prosemirror-commands": "^1.0.4",
- "@types/prosemirror-dev-tools": "^3.0.6",
"@types/prosemirror-history": "^1.0.3",
"@types/prosemirror-inputrules": "^1.0.4",
"@types/prosemirror-keymap": "^1.0.4",
@@ -679,17 +675,6 @@
"node": ">=6.9.0"
}
},
- "node_modules/@compiled/react": {
- "version": "0.11.4",
- "resolved": "https://registry.npmjs.org/@compiled/react/-/react-0.11.4.tgz",
- "integrity": "sha512-mtnEUFM7w/5xABWWWj3wW0vjS/cHSg0PAttJC+hOpQ5z5qGZCwk43Gy8Hfjruxvll73igJ5DSMzcAyek6DMKjw==",
- "dependencies": {
- "csstype": "^3.1.1"
- },
- "peerDependencies": {
- "react": ">= 16.12.0"
- }
- },
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@@ -2503,11 +2488,6 @@
"integrity": "sha512-8iHVLHsCCOBKjCF2KwFe0p9Z3rfM9mL+sSP8btyR5vTjJRAqpBYD28/ZLgXPf0pjG1VxOvtCV/BgXkQbpSe8Hw==",
"dev": true
},
- "node_modules/@types/base16": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/@types/base16/-/base16-1.0.5.tgz",
- "integrity": "sha512-OzOWrTluG9cwqidEzC/Q6FAmIPcnZfm8BFRlIx0+UIUqnuAmi5OS88O0RpT3Yz6qdmqObvUhasrbNsCofE4W9A=="
- },
"node_modules/@types/bcrypt-nodejs": {
"version": "0.0.31",
"resolved": "https://registry.npmjs.org/@types/bcrypt-nodejs/-/bcrypt-nodejs-0.0.31.tgz",
@@ -3031,16 +3011,6 @@
"@types/google.maps": "*"
}
},
- "node_modules/@types/google-maps-react": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@types/google-maps-react/-/google-maps-react-2.0.5.tgz",
- "integrity": "sha512-qcsYlHiNH169Vf7jmkEwbzBDqBfqqzYkTgK1vL7qkWVZI04wFESADYVITuQunrZ9swY/SG+tTWUIXMlY4W8byw==",
- "deprecated": "This is a stub types definition. google-maps-react provides its own type definitions, so you do not need this installed.",
- "dev": true,
- "dependencies": {
- "google-maps-react": "*"
- }
- },
"node_modules/@types/google.maps": {
"version": "3.53.5",
"resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.53.5.tgz",
@@ -3121,7 +3091,8 @@
"node_modules/@types/lodash": {
"version": "4.14.202",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
- "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ=="
+ "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
+ "dev": true
},
"node_modules/@types/mdast": {
"version": "4.0.3",
@@ -3328,15 +3299,6 @@
"prosemirror-commands": "*"
}
},
- "node_modules/@types/prosemirror-dev-tools": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/@types/prosemirror-dev-tools/-/prosemirror-dev-tools-3.0.6.tgz",
- "integrity": "sha512-zARROV118nwc+sX7W+0ea4cffqUeRNOSac0jttSpJ921aS6w++Be+RakAgGiTqoRpPV+J+wKomMR/RuKBAlEMg==",
- "dev": true,
- "dependencies": {
- "prosemirror-view": "^1.24.0"
- }
- },
"node_modules/@types/prosemirror-history": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@types/prosemirror-history/-/prosemirror-history-1.3.0.tgz",
@@ -5158,11 +5120,6 @@
"node": ">= 0.4"
}
},
- "node_modules/base16": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
- "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ=="
- },
"node_modules/Base64": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz",
@@ -9196,34 +9153,6 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
- "node_modules/concat-stream": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
- "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
- "engines": [
- "node >= 0.8"
- ],
- "dependencies": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^2.2.2",
- "typedarray": "^0.0.6"
- }
- },
- "node_modules/concat-stream/node_modules/readable-stream": {
- "version": "2.3.7",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
- "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
"node_modules/confusing-browser-globals": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
@@ -10936,11 +10865,6 @@
"node": ">=0.3.1"
}
},
- "node_modules/diff-match-patch": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
- "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
- },
"node_modules/digest-fetch": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz",
@@ -11314,19 +11238,6 @@
"node": ">=4"
}
},
- "node_modules/equation-editor-react": {
- "version": "0.0.10",
- "resolved": "https://registry.npmjs.org/equation-editor-react/-/equation-editor-react-0.0.10.tgz",
- "integrity": "sha512-m1fBISnB1Z9OO9QzrwoOiTO6y/psA8+1Bc+s2bkRhG0hQAmMK5NKrr8ommAka0sDp7+OvXs+pqJfZdq4o3X+wA==",
- "dependencies": {
- "jquery": "^3.4.1",
- "mathquill": "^0.10.1-a"
- },
- "peerDependencies": {
- "react": "^16.0.0",
- "react-dom": "^16.0.0"
- }
- },
"node_modules/error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -14966,15 +14877,6 @@
"node": ">=14"
}
},
- "node_modules/google-maps-react": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/google-maps-react/-/google-maps-react-2.0.6.tgz",
- "integrity": "sha512-M8Eo9WndfQEfxcmm6yRq03qdJgw1x6rQmJ9DN+a+xPQ3K7yNDGkVDbinrf4/8vcox7nELbeopbm4bpefKewWfQ==",
- "peerDependencies": {
- "react": "~0.14.8 || ^15.0.0 || ^16.0.0",
- "react-dom": "~0.14.8 || ^15.0.0 || ^16.0.0"
- }
- },
"node_modules/googleapis": {
"version": "129.0.0",
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-129.0.0.tgz",
@@ -15514,17 +15416,6 @@
"util-deprecate": "~1.0.1"
}
},
- "node_modules/html": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/html/-/html-1.0.0.tgz",
- "integrity": "sha1-pUT6nqVJK/s6LMqCEKEL57WvH2E=",
- "dependencies": {
- "concat-stream": "^1.4.7"
- },
- "bin": {
- "html": "bin/html.js"
- }
- },
"node_modules/html-encoding-sniffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
@@ -17194,63 +17085,6 @@
"regenerator-runtime": "^0.13.3"
}
},
- "node_modules/jotai": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/jotai/-/jotai-1.13.1.tgz",
- "integrity": "sha512-RUmH1S4vLsG3V6fbGlKzGJnLrDcC/HNb5gH2AeA9DzuJknoVxSGvvg8OBB7lke+gDc4oXmdVsaKn/xDUhWZ0vw==",
- "engines": {
- "node": ">=12.20.0"
- },
- "peerDependencies": {
- "@babel/core": "*",
- "@babel/template": "*",
- "jotai-devtools": "*",
- "jotai-immer": "*",
- "jotai-optics": "*",
- "jotai-redux": "*",
- "jotai-tanstack-query": "*",
- "jotai-urql": "*",
- "jotai-valtio": "*",
- "jotai-xstate": "*",
- "jotai-zustand": "*",
- "react": ">=16.8"
- },
- "peerDependenciesMeta": {
- "@babel/core": {
- "optional": true
- },
- "@babel/template": {
- "optional": true
- },
- "jotai-devtools": {
- "optional": true
- },
- "jotai-immer": {
- "optional": true
- },
- "jotai-optics": {
- "optional": true
- },
- "jotai-redux": {
- "optional": true
- },
- "jotai-tanstack-query": {
- "optional": true
- },
- "jotai-urql": {
- "optional": true
- },
- "jotai-valtio": {
- "optional": true
- },
- "jotai-xstate": {
- "optional": true
- },
- "jotai-zustand": {
- "optional": true
- }
- }
- },
"node_modules/jpeg-js": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz",
@@ -17490,21 +17324,6 @@
"json5": "lib/cli.js"
}
},
- "node_modules/jsondiffpatch": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.4.1.tgz",
- "integrity": "sha512-t0etAxTUk1w5MYdNOkZBZ8rvYYN5iL+2dHCCx/DpkFm/bW28M6y5nUS83D4XdZiHy35Fpaw6LBb+F88fHZnVCw==",
- "dependencies": {
- "chalk": "^2.3.0",
- "diff-match-patch": "^1.0.0"
- },
- "bin": {
- "jsondiffpatch": "bin/jsondiffpatch"
- },
- "engines": {
- "node": ">=8.17.0"
- }
- },
"node_modules/jsonfile": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
@@ -17894,16 +17713,6 @@
"resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz",
"integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw="
},
- "node_modules/lodash.curry": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz",
- "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA=="
- },
- "node_modules/lodash.debounce": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
- },
"node_modules/lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
@@ -20157,11 +19966,6 @@
"resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz",
"integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ=="
},
- "node_modules/nanoid": {
- "version": "2.1.11",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz",
- "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA=="
- },
"node_modules/nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -20491,9 +20295,9 @@
"integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg=="
},
"node_modules/npm": {
- "version": "10.2.4",
- "resolved": "https://registry.npmjs.org/npm/-/npm-10.2.4.tgz",
- "integrity": "sha512-umEuYneVEYO9KoEEI8n2sSGmNQeqco/3BSeacRlqIkCzw4E7XGtYSWMeJobxzr6hZ2n9cM+u5TsMTcC5bAgoWA==",
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/npm/-/npm-10.2.5.tgz",
+ "integrity": "sha512-lXdZ7titEN8CH5YJk9C/aYRU9JeDxQ4d8rwIIDsvH3SMjLjHTukB2CFstMiB30zXs4vCrPN2WH6cDq1yHBeJAw==",
"bundleDependencies": [
"@isaacs/string-locale-compare",
"@npmcli/arborist",
@@ -20579,7 +20383,7 @@
"@sigstore/tuf": "^2.2.0",
"abbrev": "^2.0.0",
"archy": "~1.0.0",
- "cacache": "^18.0.0",
+ "cacache": "^18.0.1",
"chalk": "^5.3.0",
"ci-info": "^4.0.0",
"cli-columns": "^4.0.0",
@@ -20593,7 +20397,7 @@
"ini": "^4.1.1",
"init-package-json": "^6.0.0",
"is-cidr": "^5.0.3",
- "json-parse-even-better-errors": "^3.0.0",
+ "json-parse-even-better-errors": "^3.0.1",
"libnpmaccess": "^8.0.1",
"libnpmdiff": "^6.0.3",
"libnpmexec": "^7.0.4",
@@ -20622,7 +20426,7 @@
"npm-user-validate": "^2.0.0",
"npmlog": "^7.0.1",
"p-map": "^4.0.0",
- "pacote": "^17.0.4",
+ "pacote": "^17.0.5",
"parse-conflict-json": "^3.0.1",
"proc-log": "^3.0.0",
"qrcode-terminal": "^0.12.0",
@@ -20742,7 +20546,7 @@
}
},
"node_modules/npm/node_modules/@npmcli/arborist": {
- "version": "7.2.1",
+ "version": "7.2.2",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -20788,7 +20592,7 @@
}
},
"node_modules/npm/node_modules/@npmcli/config": {
- "version": "8.0.2",
+ "version": "8.0.3",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -21217,7 +21021,7 @@
}
},
"node_modules/npm/node_modules/cacache": {
- "version": "18.0.0",
+ "version": "18.0.1",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -21226,7 +21030,7 @@
"glob": "^10.2.2",
"lru-cache": "^10.0.1",
"minipass": "^7.0.3",
- "minipass-collect": "^1.0.2",
+ "minipass-collect": "^2.0.1",
"minipass-flush": "^1.0.5",
"minipass-pipeline": "^1.2.4",
"p-map": "^4.0.0",
@@ -21745,7 +21549,7 @@
"license": "BSD-3-Clause"
},
"node_modules/npm/node_modules/ignore-walk": {
- "version": "6.0.3",
+ "version": "6.0.4",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -21870,7 +21674,7 @@
}
},
"node_modules/npm/node_modules/json-parse-even-better-errors": {
- "version": "3.0.0",
+ "version": "3.0.1",
"inBundle": true,
"license": "MIT",
"engines": {
@@ -21904,7 +21708,7 @@
"license": "MIT"
},
"node_modules/npm/node_modules/libnpmaccess": {
- "version": "8.0.1",
+ "version": "8.0.2",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -21916,7 +21720,7 @@
}
},
"node_modules/npm/node_modules/libnpmdiff": {
- "version": "6.0.3",
+ "version": "6.0.4",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -21935,7 +21739,7 @@
}
},
"node_modules/npm/node_modules/libnpmexec": {
- "version": "7.0.4",
+ "version": "7.0.5",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -21956,7 +21760,7 @@
}
},
"node_modules/npm/node_modules/libnpmfund": {
- "version": "5.0.1",
+ "version": "5.0.2",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -21967,7 +21771,7 @@
}
},
"node_modules/npm/node_modules/libnpmhook": {
- "version": "10.0.0",
+ "version": "10.0.1",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -21979,7 +21783,7 @@
}
},
"node_modules/npm/node_modules/libnpmorg": {
- "version": "6.0.1",
+ "version": "6.0.2",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -21991,7 +21795,7 @@
}
},
"node_modules/npm/node_modules/libnpmpack": {
- "version": "6.0.3",
+ "version": "6.0.4",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -22005,7 +21809,7 @@
}
},
"node_modules/npm/node_modules/libnpmpublish": {
- "version": "9.0.2",
+ "version": "9.0.3",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -22023,7 +21827,7 @@
}
},
"node_modules/npm/node_modules/libnpmsearch": {
- "version": "7.0.0",
+ "version": "7.0.1",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -22034,7 +21838,7 @@
}
},
"node_modules/npm/node_modules/libnpmteam": {
- "version": "6.0.0",
+ "version": "6.0.1",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -22046,7 +21850,7 @@
}
},
"node_modules/npm/node_modules/libnpmversion": {
- "version": "5.0.1",
+ "version": "5.0.2",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -22061,12 +21865,9 @@
}
},
"node_modules/npm/node_modules/lru-cache": {
- "version": "10.0.2",
+ "version": "10.1.0",
"inBundle": true,
"license": "ISC",
- "dependencies": {
- "semver": "^7.3.5"
- },
"engines": {
"node": "14 || >=16.14"
}
@@ -22115,25 +21916,14 @@
}
},
"node_modules/npm/node_modules/minipass-collect": {
- "version": "1.0.2",
- "inBundle": true,
- "license": "ISC",
- "dependencies": {
- "minipass": "^3.0.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/npm/node_modules/minipass-collect/node_modules/minipass": {
- "version": "3.3.6",
+ "version": "2.0.1",
"inBundle": true,
"license": "ISC",
"dependencies": {
- "yallist": "^4.0.0"
+ "minipass": "^7.0.3"
},
"engines": {
- "node": ">=8"
+ "node": ">=16 || 14 >=14.17"
}
},
"node_modules/npm/node_modules/minipass-fetch": {
@@ -22397,11 +22187,11 @@
}
},
"node_modules/npm/node_modules/npm-packlist": {
- "version": "8.0.0",
+ "version": "8.0.1",
"inBundle": true,
"license": "ISC",
"dependencies": {
- "ignore-walk": "^6.0.0"
+ "ignore-walk": "^6.0.4"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
@@ -22487,7 +22277,7 @@
}
},
"node_modules/npm/node_modules/pacote": {
- "version": "17.0.4",
+ "version": "17.0.5",
"inBundle": true,
"license": "ISC",
"dependencies": {
@@ -24544,30 +24334,6 @@
"prosemirror-transform": "^1.0.0"
}
},
- "node_modules/prosemirror-dev-tools": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/prosemirror-dev-tools/-/prosemirror-dev-tools-4.0.0.tgz",
- "integrity": "sha512-fF1AqJJa/ojVJTtc6WvygVQWFQI1zo37dewn0BQEKNLUfdJ4PRbqIYIFfh30wQhe8XcWw7J1ZidHZHz0a8VoYQ==",
- "dependencies": {
- "@babel/runtime": "^7.18.6",
- "@compiled/react": "^0.11.1",
- "html": "^1.0.0",
- "jotai": "^1.10.0",
- "jsondiffpatch": "^0.4.1",
- "nanoid": "^2.1.11",
- "prosemirror-model": ">=1.0.0",
- "prosemirror-state": ">=1.0.0",
- "react-dock": "^0.6.0",
- "react-json-tree": "^0.17.0"
- },
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "react": ">=16.8.0",
- "react-dom": ">=16.8.0"
- }
- },
"node_modules/prosemirror-find-replace": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/prosemirror-find-replace/-/prosemirror-find-replace-0.9.0.tgz",
@@ -25060,29 +24826,6 @@
"react": ">=16.3.0"
}
},
- "node_modules/react-base16-styling": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.9.1.tgz",
- "integrity": "sha512-1s0CY1zRBOQ5M3T61wetEpvQmsYSNtWEcdYzyZNxKa8t7oDvaOn9d21xrGezGAHFWLM7SHcktPuPTrvoqxSfKw==",
- "dependencies": {
- "@babel/runtime": "^7.16.7",
- "@types/base16": "^1.0.2",
- "@types/lodash": "^4.14.178",
- "base16": "^1.0.0",
- "color": "^3.2.1",
- "csstype": "^3.0.10",
- "lodash.curry": "^4.1.1"
- }
- },
- "node_modules/react-base16-styling/node_modules/color": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
- "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
- "dependencies": {
- "color-convert": "^1.9.3",
- "color-string": "^1.6.0"
- }
- },
"node_modules/react-color": {
"version": "2.19.3",
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz",
@@ -25151,22 +24894,6 @@
"react-dom": "^16.9.0 || ^17 || ^18"
}
},
- "node_modules/react-dock": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/react-dock/-/react-dock-0.6.0.tgz",
- "integrity": "sha512-jEOhv1s+pqRQ4JxgUw4XUotnprOehZ23mqchf3whxYXnvNgTQOXCxh6bpcqW8P6OybIk2bYO18r3qimZ3ypCbg==",
- "dependencies": {
- "@babel/runtime": "^7.18.3",
- "@types/lodash": "^4.14.182",
- "@types/prop-types": "^15.7.5",
- "lodash.debounce": "^4.0.8",
- "prop-types": "^15.8.1"
- },
- "peerDependencies": {
- "@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0",
- "react": "^16.3.0 || ^17.0.0 || ^18.0.0"
- }
- },
"node_modules/react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
@@ -25264,22 +24991,6 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
- "node_modules/react-json-tree": {
- "version": "0.17.0",
- "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.17.0.tgz",
- "integrity": "sha512-hcWjibI/fAvsKnfYk+lka5OrE1Lvb1jH5pSnFhIU5T8cCCxB85r6h/NOzDPggSSgErjmx4rl3+2EkeclIKBOhg==",
- "dependencies": {
- "@babel/runtime": "^7.18.3",
- "@types/lodash": "^4.14.182",
- "@types/prop-types": "^15.7.5",
- "prop-types": "^15.8.1",
- "react-base16-styling": "^0.9.1"
- },
- "peerDependencies": {
- "@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0",
- "react": "^16.3.0 || ^17.0.0 || ^18.0.0"
- }
- },
"node_modules/react-jsx-parser": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/react-jsx-parser/-/react-jsx-parser-1.29.0.tgz",
@@ -28953,11 +28664,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
- },
"node_modules/typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
diff --git a/package.json b/package.json
index 92d5ef856..7bf0bba05 100644
--- a/package.json
+++ b/package.json
@@ -41,7 +41,6 @@
"@types/express-session": "^1.17.10",
"@types/express-validator": "^3.0.0",
"@types/file-saver": "^2.0.7",
- "@types/google-maps-react": "^2.0.5",
"@types/jquery": "^3.5.29",
"@types/libxmljs": "^0.18.12",
"@types/lodash": "^4.14.202",
@@ -56,7 +55,6 @@
"@types/passport-local": "^1.0.38",
"@types/pdfjs-dist": "^2.10.378",
"@types/prosemirror-commands": "^1.0.4",
- "@types/prosemirror-dev-tools": "^3.0.6",
"@types/prosemirror-history": "^1.0.3",
"@types/prosemirror-inputrules": "^1.0.4",
"@types/prosemirror-keymap": "^1.0.4",
@@ -182,7 +180,6 @@
"D": "^1.0.0",
"d3": "^7.8.5",
"depcheck": "^1.4.7",
- "equation-editor-react": "^0.0.10",
"exif": "^0.6.0",
"exifr": "^7.1.3",
"express": "^4.18.2",
@@ -203,7 +200,6 @@
"function-plot": "^1.23.3",
"golden-layout": "^2.6.0",
"google-auth-library": "^9.4.1",
- "google-maps-react": "^2.0.6",
"googleapis": "^129.0.0",
"googlephotos": "^0.3.5",
"got": "^14.0.0",
@@ -225,6 +221,7 @@
"jszip": "^3.10.1",
"lodash": "^4.17.21",
"material-ui": "^0.20.2",
+ "mathquill": "^0.10.1-a",
"md5-file": "^5.0.0",
"memorystream": "^0.3.1",
"mobile-detect": "^1.4.5",
@@ -238,7 +235,7 @@
"nodemailer": "^6.9.7",
"nodemon": "^3.0.2",
"normalize.css": "^8.0.1",
- "npm": "^10.2.4",
+ "npm": "^10.2.5",
"openai": "^4.20.1",
"p-limit": "^5.0.0",
"passport": "^0.7.0",
@@ -251,7 +248,6 @@
"probe-image-size": "^7.2.3",
"process": "^0.11.10",
"prosemirror-commands": "^1.5.2",
- "prosemirror-dev-tools": "^4.0.0",
"prosemirror-find-replace": "^0.9.0",
"prosemirror-history": "^1.3.2",
"prosemirror-inputrules": "^1.3.0",
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index cd263f82a..23413b9d1 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -1,4 +1,4 @@
-import EquationEditor from 'equation-editor-react';
+import EquationEditor from './formattedText/EquationEditor';
import { action, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 398d1255e..69723b171 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -794,17 +794,6 @@ export class MapBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
/>
))}
</div>
- {/* <MapBoxInfoWindow
- key={Docs.Create.MapMarkerDocument(NumCast(40), NumCast(40), false, [], {})[Id]}
- {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
- place={Docs.Create.MapMarkerDocument(NumCast(40), NumCast(40), false, [], {})}
- markerMap={this.markerMap}
- PanelWidth={this.infoWidth}
- PanelHeight={this.infoHeight}
- moveDocument={this.moveDocument}
- isAnyChildContentActive={this.isAnyChildContentActive}
- whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
- /> */}
</div>
{/* </LoadScript > */}
<div className="mapBox-sidebar" style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx
index a77bfc50a..39ed6a47e 100644
--- a/src/client/views/nodes/MapBox/MapBox2.tsx
+++ b/src/client/views/nodes/MapBox/MapBox2.tsx
@@ -1,597 +1,597 @@
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Autocomplete, GoogleMap, GoogleMapProps, Marker } from '@react-google-maps/api';
-import { action, computed, IReactionDisposer, observable, ObservableMap, runInAction } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
-import { Id } from '../../../../fields/FieldSymbols';
-import { NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils';
-import { Docs } from '../../../documents/Documents';
-import { DragManager } from '../../../util/DragManager';
-import { SnappingManager } from '../../../util/SnappingManager';
-import { UndoManager } from '../../../util/UndoManager';
-import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
-import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
-import { Colors } from '../../global/globalEnums';
-import { AnchorMenu } from '../../pdf/AnchorMenu';
-import { Annotation } from '../../pdf/Annotation';
-import { SidebarAnnos } from '../../SidebarAnnos';
-import { FieldView, FieldViewProps } from '../FieldView';
-import { PinProps } from '../trails';
-import './MapBox2.scss';
-import { MapBoxInfoWindow } from './MapBoxInfoWindow';
-
-/**
- * MapBox2 architecture:
- * Main component: MapBox2.tsx
- * Supporting Components: SidebarAnnos, CollectionStackingView
- *
- * MapBox2 is a node that extends the ViewBoxAnnotatableComponent. Similar to PDFBox and WebBox, it supports interaction between sidebar content and document content.
- * The main body of MapBox2 uses Google Maps API to allow location retrieval, adding map markers, pan and zoom, and open street view.
- * Dash Document architecture is integrated with Maps API: When drag and dropping documents with ExifData (gps Latitude and Longitude information) available,
- * sidebarAddDocument function checks if the document contains lat & lng information, if it does, then the document is added to both the sidebar and the infowindow (a pop up corresponding to a map marker--pin on map).
- * The lat and lng field of the document is filled when importing (spec see ConvertDMSToDD method and processFileUpload method in Documents.ts).
- * A map marker is considered a document that contains a collection with stacking view of documents, it has a lat, lng location, which is passed to Maps API's custom marker (red pin) to be rendered on the google maps
- */
-
-// const _global = (window /* browser */ || global /* node */) as any;
-
-const mapContainerStyle = {
- height: '100%',
-};
-
-const defaultCenter = {
- lat: 42.360081,
- lng: -71.058884,
-};
-
-const mapOptions = {
- fullscreenControl: false,
-};
-
-const apiKey = process.env.GOOGLE_MAPS;
-
-const script = document.createElement('script');
-script.defer = true;
-script.async = true;
-script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places,drawing`;
-console.log(script.src);
-document.head.appendChild(script);
-
-/**
- * Consider integrating later: allows for drawing, circling, making shapes on map
- */
-// const drawingManager = new window.google.maps.drawing.DrawingManager({
-// drawingControl: true,
-// drawingControlOptions: {
-// position: google.maps.ControlPosition.TOP_RIGHT,
-// drawingModes: [
-// google.maps.drawing.OverlayType.MARKER,
-// // currently we are not supporting the following drawing mode on map, a thought for future development
-// google.maps.drawing.OverlayType.CIRCLE,
-// google.maps.drawing.OverlayType.POLYLINE,
-// ],
-// },
-// });
-
-// options for searchbox in Google Maps Places Autocomplete API
-const options = {
- fields: ['formatted_address', 'geometry', 'name'], // note: level of details is charged by item per retrieval, not recommended to return all fields
- strictBounds: false,
- types: ['establishment'], // type pf places, subject of change according to user need
-} as google.maps.places.AutocompleteOptions;
-
-@observer
-export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps & Partial<GoogleMapProps>>() {
- private _dropDisposer?: DragManager.DragDropDisposer;
- private _disposers: { [name: string]: IReactionDisposer } = {};
- private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
- @observable private _overlayAnnoInfo: Opt<Doc>;
- showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno));
- public static LayoutString(fieldKey: string) {
- return FieldView.LayoutString(MapBox2, fieldKey);
- }
- public get SidebarKey() {
- return this.fieldKey + '_sidebar';
- }
- private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void);
- @computed get inlineTextAnnotations() {
- return this.allMapMarkers.filter(a => a.text_inlineAnnotations);
- }
-
- @observable private _map: google.maps.Map = null as unknown as google.maps.Map;
- @observable private selectedPlace: Doc | undefined;
- @observable private markerMap: { [id: string]: google.maps.Marker } = {};
- @observable private center = navigator.geolocation ? navigator.geolocation.getCurrentPosition : defaultCenter;
- @observable private inputRef = React.createRef<HTMLInputElement>();
- @observable private searchMarkers: google.maps.Marker[] = [];
- @observable private searchBox = new window.google.maps.places.Autocomplete(this.inputRef.current!, options);
- @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
- @computed get allSidebarDocs() {
- return DocListCast(this.dataDoc[this.SidebarKey]);
- }
- @computed get allMapMarkers() {
- return DocListCast(this.dataDoc[this.annotationKey]);
- }
- @observable private toggleAddMarker = false;
-
- @observable _showSidebar = false;
- @computed get SidebarShown() {
- return this._showSidebar || this.layoutDoc._layout_showSidebar ? true : false;
- }
-
- static _canAnnotate = true;
- static _hadSelection: boolean = false;
- private _sidebarRef = React.createRef<SidebarAnnos>();
- private _ref: React.RefObject<HTMLDivElement> = React.createRef();
-
- componentDidMount() {
- this.props.setContentView?.(this);
- }
-
- @action
- private setSearchBox = (searchBox: any) => {
- this.searchBox = searchBox;
- };
-
- // iterate allMarkers to size, center, and zoom map to contain all markers
- private fitBounds = (map: google.maps.Map) => {
- const curBounds = map.getBounds() ?? new window.google.maps.LatLngBounds();
- const isFitting = this.allMapMarkers.reduce((fits, place) => fits && curBounds?.contains({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), true as boolean);
- !isFitting && map.fitBounds(this.allMapMarkers.reduce((bounds, place) => bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), new window.google.maps.LatLngBounds()));
- };
-
- /**
- * Custom control for add marker button
- * @param controlDiv
- * @param map
- */
- private CenterControl = () => {
- const controlDiv = document.createElement('div');
- controlDiv.className = 'MapBox2-addMarker';
- // Set CSS for the control border.
- const controlUI = document.createElement('div');
- controlUI.style.backgroundColor = '#fff';
- controlUI.style.borderRadius = '3px';
- controlUI.style.cursor = 'pointer';
- controlUI.style.marginTop = '10px';
- controlUI.style.borderRadius = '4px';
- controlUI.style.marginBottom = '22px';
- controlUI.style.textAlign = 'center';
- controlUI.style.position = 'absolute';
- controlUI.style.width = '32px';
- controlUI.style.height = '32px';
- controlUI.title = 'Click to toggle marker mode. In marker mode, click on map to place a marker.';
-
- const plIcon = document.createElement('img');
- plIcon.src = 'https://cdn4.iconfinder.com/data/icons/wirecons-free-vector-icons/32/add-256.png';
- plIcon.style.color = 'rgb(25,25,25)';
- plIcon.style.fontFamily = 'Roboto,Arial,sans-serif';
- plIcon.style.fontSize = '16px';
- plIcon.style.lineHeight = '32px';
- plIcon.style.left = '18';
- plIcon.style.top = '15';
- plIcon.style.position = 'absolute';
- plIcon.width = 14;
- plIcon.height = 14;
- plIcon.innerHTML = 'Add';
- controlUI.appendChild(plIcon);
-
- // Set CSS for the control interior.
- const markerIcon = document.createElement('img');
- markerIcon.src = 'https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678111-map-marker-1024.png';
- markerIcon.style.color = 'rgb(25,25,25)';
- markerIcon.style.fontFamily = 'Roboto,Arial,sans-serif';
- markerIcon.style.fontSize = '16px';
- markerIcon.style.lineHeight = '32px';
- markerIcon.style.left = '-2';
- markerIcon.style.top = '1';
- markerIcon.width = 30;
- markerIcon.height = 30;
- markerIcon.style.position = 'absolute';
- markerIcon.innerHTML = 'Add';
- controlUI.appendChild(markerIcon);
-
- // Setup the click event listeners
- controlUI.addEventListener('click', () => {
- if (this.toggleAddMarker === true) {
- this.toggleAddMarker = false;
- console.log('add marker button status:' + this.toggleAddMarker);
- controlUI.style.backgroundColor = '#fff';
- markerIcon.style.color = 'rgb(25,25,25)';
- } else {
- this.toggleAddMarker = true;
- console.log('add marker button status:' + this.toggleAddMarker);
- controlUI.style.backgroundColor = '#4476f7';
- markerIcon.style.color = 'rgb(255,255,255)';
- }
- });
- controlDiv.appendChild(controlUI);
- return controlDiv;
- };
-
- /**
- * Place the marker on google maps & store the empty marker as a MapMarker Document in allMarkers list
- * @param position - the LatLng position where the marker is placed
- * @param map
- */
- @action
- private placeMarker = (position: google.maps.LatLng, map: google.maps.Map) => {
- const marker = new google.maps.Marker({
- position: position,
- map: map,
- });
- map.panTo(position);
- const mapMarker = Docs.Create.PushpinDocument(NumCast(position.lat()), NumCast(position.lng()), false, [], {});
- this.addDocument(mapMarker, this.annotationKey);
- };
-
- _loadPending = true;
- /**
- * store a reference to google map instance
- * setup the drawing manager on the top right corner of map
- * fit map bounds to contain all markers
- * @param map
- */
- @action
- private loadHandler = (map: google.maps.Map) => {
- this._map = map;
- this._loadPending = true;
- const centerControlDiv = this.CenterControl();
- map.controls[google.maps.ControlPosition.TOP_RIGHT].push(centerControlDiv);
- //drawingManager.setMap(map);
- // if (navigator.geolocation) {
- // navigator.geolocation.getCurrentPosition(
- // (position: Position) => {
- // const pos = {
- // lat: position.coords.latitude,
- // lng: position.coords.longitude,
- // };
- // this._map.setCenter(pos);
- // }
- // );
- // } else {
- // alert("Your geolocation is not supported by browser.")
- // };
- map.setZoom(NumCast(this.dataDoc.map_zoom, 2.5));
- map.setCenter(new google.maps.LatLng(NumCast(this.dataDoc.mapLat), NumCast(this.dataDoc.mapLng)));
- setTimeout(() => {
- if (this._loadPending && this._map.getBounds()) {
- this._loadPending = false;
- this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
- }
- }, 250);
- // listener to addmarker event
- this._map.addListener('click', (e: MouseEvent) => {
- if (this.toggleAddMarker === true) {
- this.placeMarker((e as any).latLng, map);
- }
- });
- };
-
- @action
- centered = () => {
- if (this._loadPending && this._map.getBounds()) {
- this._loadPending = false;
- this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
- }
- this.dataDoc.mapLat = this._map.getCenter()?.lat();
- this.dataDoc.mapLng = this._map.getCenter()?.lng();
- };
-
- @action
- zoomChanged = () => {
- if (this._loadPending && this._map.getBounds()) {
- this._loadPending = false;
- this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
- }
- this.dataDoc.map_zoom = this._map.getZoom();
- };
-
- /**
- * Load and render all map markers
- * @param marker
- * @param place
- */
- @action
- private markerLoadHandler = (marker: google.maps.Marker, place: Doc) => {
- place[Id] ? (this.markerMap[place[Id]] = marker) : null;
- };
-
- /**
- * on clicking the map marker, set the selected place to the marker document & set infowindowopen to be true
- * @param e
- * @param place
- */
- @action
- private markerClickHandler = (e: google.maps.MapMouseEvent, place: Doc) => {
- // set which place was clicked
- this.selectedPlace = place;
- place.infoWindowOpen = true;
- };
-
- /**
- * Called when dragging documents into map sidebar or directly into infowindow; to create a map marker, ref to MapMarkerDocument in Documents.ts
- * @param doc
- * @param sidebarKey
- * @returns
- */
- sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
- console.log('print all sidebar Docs');
- if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
- const docs = doc instanceof Doc ? [doc] : doc;
- docs.forEach(doc => {
- if (doc.lat !== undefined && doc.lng !== undefined) {
- const existingMarker = this.allMapMarkers.find(marker => marker.lat === doc.lat && marker.lng === doc.lng);
- if (existingMarker) {
- Doc.AddDocToList(existingMarker, 'data', doc);
- } else {
- const marker = Docs.Create.PushpinDocument(NumCast(doc.lat), NumCast(doc.lng), false, [doc], {});
- this.addDocument(marker, this.annotationKey);
- }
- }
- }); //add to annotation list
-
- return this.addDocument(doc, sidebarKey); // add to sidebar list
- };
-
- /**
- * Removing documents from the sidebar
- * @param doc
- * @param sidebarKey
- * @returns
- */
- sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
- if (this.layoutDoc._layout_showSidebar) this.toggleSidebar();
- const docs = doc instanceof Doc ? [doc] : doc;
- return this.removeDocument(doc, sidebarKey);
- };
-
- /**
- * Toggle sidebar onclick the tiny comment button on the top right corner
- * @param e
- */
- sidebarBtnDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(
- this,
- e,
- (e, down, delta) =>
- runInAction(() => {
- const localDelta = this.props
- .ScreenToLocalTransform()
- .scale(this.props.NativeDimScaling?.() || 1)
- .transformDirection(delta[0], delta[1]);
- const fullWidth = NumCast(this.layoutDoc._width);
- const mapWidth = fullWidth - this.sidebarWidth();
- if (this.sidebarWidth() + localDelta[0] > 0) {
- this._showSidebar = true;
- this.layoutDoc._width = fullWidth + localDelta[0];
- this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
- } else {
- this._showSidebar = false;
- this.layoutDoc._width = mapWidth;
- this.layoutDoc._layout_sidebarWidthPercent = '0%';
- }
- return false;
- }),
- emptyFunction,
- () => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar map')
- );
- };
-
- sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
- @computed get layout_sidebarWidthPercent() {
- return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
- }
- @computed get sidebarColor() {
- return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
- }
-
- /**
- * function that reads the place inputed from searchbox, then zoom in on the location that's been autocompleted;
- * add a customized temporary marker on the map
- */
- @action
- private handlePlaceChanged = () => {
- const place = this.searchBox.getPlace();
-
- if (!place.geometry || !place.geometry.location) {
- // user entered the name of a place that wasn't suggested & pressed the enter key, or place details request failed
- window.alert("No details available for input: '" + place.name + "'");
- return;
- }
-
- // zoom in on the location of the search result
- if (place.geometry.viewport) {
- this._map.fitBounds(place.geometry.viewport);
- } else {
- this._map.setCenter(place.geometry.location);
- this._map.setZoom(17);
- }
-
- // customize icon => customized icon for the nature of the location selected
- const icon = {
- url: place.icon as string,
- size: new google.maps.Size(71, 71),
- origin: new google.maps.Point(0, 0),
- anchor: new google.maps.Point(17, 34),
- scaledSize: new google.maps.Size(25, 25),
- };
-
- // put temporary cutomized marker on searched location
- this.searchMarkers.forEach(marker => {
- marker.setMap(null);
- });
- this.searchMarkers = [];
- this.searchMarkers.push(
- new window.google.maps.Marker({
- map: this._map,
- icon,
- title: place.name,
- position: place.geometry.location,
- })
- );
- };
-
- /**
- * Handles toggle of sidebar on click the little comment button
- */
- @computed get sidebarHandle() {
- return (
- <div
- className="MapBox2-overlayButton-sidebar"
- key="sidebar"
- title="Toggle Sidebar"
- style={{
- display: !this.props.isContentActive() ? 'none' : undefined,
- top: StrCast(this.layoutDoc._layout_showTitle) === 'title' ? 20 : 5,
- backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
- }}
- onPointerDown={this.sidebarBtnDown}>
- <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={'comment-alt'} size="sm" />
- </div>
- );
- }
-
- // TODO: Adding highlight box layer to Maps
- @action
- toggleSidebar = () => {
- //1.2 * w * ? = .2 * w .2/1.2
- const prevWidth = this.sidebarWidth();
- this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%';
- this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
- };
-
- sidebarDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), true);
- };
- sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
- const bounds = this._ref.current!.getBoundingClientRect();
- this.layoutDoc._layout_sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%';
- this.layoutDoc._layout_showSidebar = this.layoutDoc._layout_sidebarWidthPercent !== '0%';
- e.preventDefault();
- return false;
- };
-
- setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func);
-
- addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => {
- return this.addDocument(doc, annotationKey);
- };
-
- pointerEvents = () => {
- return this.props.isContentActive() === false ? 'none' : this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none';
- };
- @computed get annotationLayer() {
- return (
- <div className="MapBox2-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer}>
- {this.inlineTextAnnotations
- .sort((a, b) => NumCast(a.y) - NumCast(b.y))
- .map(anno => (
- <Annotation key={`${anno[Id]}-annotation`} {...this.props} fieldKey={this.annotationKey} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} />
- ))}
- </div>
- );
- }
-
- getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.Document;
-
- /**
- * render contents in allMapMarkers (e.g. images with exifData) into google maps as map marker
- * @returns
- */
- private renderMarkers = () => {
- return this.allMapMarkers.map(place => (
- <Marker key={place[Id]} position={{ lat: NumCast(place.lat), lng: NumCast(place.lng) }} onLoad={marker => this.markerLoadHandler(marker, place)} onClick={(e: google.maps.MapMouseEvent) => this.markerClickHandler(e, place)} />
- ));
- };
-
- // TODO: auto center on select a document in the sidebar
- private handleMapCenter = (map: google.maps.Map) => {
- // console.log("print the selected views in selectionManager:")
- // if (SelectionManager.Views().lastElement()) {
- // console.log(SelectionManager.Views().lastElement());
- // }
- };
-
- panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
- panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
- scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
- transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter];
- opaqueFilter = () => [...this.props.childFilters(), Utils.OpaqueBackgroundFilter];
- infoWidth = () => this.props.PanelWidth() / 5;
- infoHeight = () => this.props.PanelHeight() / 5;
- anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
- savedAnnotations = () => this._savedAnnotations;
-
- get MicrosoftMaps() {
- return (window as any).Microsoft.Maps;
- }
- render() {
- const renderAnnotations = (childFilters?: () => string[]) => null;
- return (
- <div className="MapBox2" ref={this._ref}>
- <div
- className="MapBox2-wrapper"
- onWheel={e => e.stopPropagation()}
- onPointerDown={async e => {
- e.button === 0 && !e.ctrlKey && e.stopPropagation();
- }}
- style={{ width: `calc(100% - ${this.layout_sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
- <div style={{ mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>
- {renderAnnotations(this.opaqueFilter)}
- {SnappingManager.GetIsDragging() ? null : renderAnnotations()}
- {this.annotationLayer}
-
- <div>
- <GoogleMap mapContainerStyle={mapContainerStyle} onZoomChanged={this.zoomChanged} onCenterChanged={this.centered} onLoad={this.loadHandler} options={mapOptions}>
- <Autocomplete onLoad={this.setSearchBox} onPlaceChanged={this.handlePlaceChanged}>
- <input className="MapBox2-input" ref={this.inputRef} type="text" onKeyDown={e => e.stopPropagation()} placeholder="Enter location" />
- </Autocomplete>
-
- {this.renderMarkers()}
- {this.allMapMarkers
- .filter(marker => marker.infoWindowOpen)
- .map(marker => (
- <MapBoxInfoWindow
- key={marker[Id]}
- {...this.props}
- setContentView={emptyFunction}
- place={marker}
- markerMap={this.markerMap}
- PanelWidth={this.infoWidth}
- PanelHeight={this.infoHeight}
- moveDocument={this.moveDocument}
- isAnyChildContentActive={this.isAnyChildContentActive}
- whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
- />
- ))}
- {/* {this.handleMapCenter(this._map)} */}
- </GoogleMap>
- </div>
- </div>
- {/* </LoadScript > */}
- <div className="MapBox2-sidebar" style={{ width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
- <SidebarAnnos
- ref={this._sidebarRef}
- {...this.props}
- fieldKey={this.fieldKey}
- Document={this.Document}
- layoutDoc={this.layoutDoc}
- dataDoc={this.dataDoc}
- usePanelWidth={true}
- showSidebar={this.SidebarShown}
- nativeWidth={NumCast(this.layoutDoc._nativeWidth)}
- whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
- PanelWidth={this.sidebarWidth}
- sidebarAddDocument={this.sidebarAddDocument}
- moveDocument={this.moveDocument}
- removeDocument={this.sidebarRemoveDocument}
- />
- </div>
- {this.sidebarHandle}
- </div>
- );
- }
-}
+// import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+// import { Autocomplete, GoogleMap, GoogleMapProps, Marker } from '@react-google-maps/api';
+// import { action, computed, IReactionDisposer, observable, ObservableMap, runInAction } from 'mobx';
+// import { observer } from 'mobx-react';
+// import * as React from 'react';
+// import { Doc, DocListCast, Opt } from '../../../../fields/Doc';
+// import { Id } from '../../../../fields/FieldSymbols';
+// import { NumCast, StrCast } from '../../../../fields/Types';
+// import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils';
+// import { Docs } from '../../../documents/Documents';
+// import { DragManager } from '../../../util/DragManager';
+// import { SnappingManager } from '../../../util/SnappingManager';
+// import { UndoManager } from '../../../util/UndoManager';
+// import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm';
+// import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent';
+// import { Colors } from '../../global/globalEnums';
+// import { AnchorMenu } from '../../pdf/AnchorMenu';
+// import { Annotation } from '../../pdf/Annotation';
+// import { SidebarAnnos } from '../../SidebarAnnos';
+// import { FieldView, FieldViewProps } from '../FieldView';
+// import { PinProps } from '../trails';
+// import './MapBox2.scss';
+// import { MapBoxInfoWindow } from './MapBoxInfoWindow';
+
+// /**
+// * MapBox2 architecture:
+// * Main component: MapBox2.tsx
+// * Supporting Components: SidebarAnnos, CollectionStackingView
+// *
+// * MapBox2 is a node that extends the ViewBoxAnnotatableComponent. Similar to PDFBox and WebBox, it supports interaction between sidebar content and document content.
+// * The main body of MapBox2 uses Google Maps API to allow location retrieval, adding map markers, pan and zoom, and open street view.
+// * Dash Document architecture is integrated with Maps API: When drag and dropping documents with ExifData (gps Latitude and Longitude information) available,
+// * sidebarAddDocument function checks if the document contains lat & lng information, if it does, then the document is added to both the sidebar and the infowindow (a pop up corresponding to a map marker--pin on map).
+// * The lat and lng field of the document is filled when importing (spec see ConvertDMSToDD method and processFileUpload method in Documents.ts).
+// * A map marker is considered a document that contains a collection with stacking view of documents, it has a lat, lng location, which is passed to Maps API's custom marker (red pin) to be rendered on the google maps
+// */
+
+// // const _global = (window /* browser */ || global /* node */) as any;
+
+// const mapContainerStyle = {
+// height: '100%',
+// };
+
+// const defaultCenter = {
+// lat: 42.360081,
+// lng: -71.058884,
+// };
+
+// const mapOptions = {
+// fullscreenControl: false,
+// };
+
+// const apiKey = process.env.GOOGLE_MAPS;
+
+// const script = document.createElement('script');
+// script.defer = true;
+// script.async = true;
+// script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places,drawing`;
+// console.log(script.src);
+// document.head.appendChild(script);
+
+// /**
+// * Consider integrating later: allows for drawing, circling, making shapes on map
+// */
+// // const drawingManager = new window.google.maps.drawing.DrawingManager({
+// // drawingControl: true,
+// // drawingControlOptions: {
+// // position: google.maps.ControlPosition.TOP_RIGHT,
+// // drawingModes: [
+// // google.maps.drawing.OverlayType.MARKER,
+// // // currently we are not supporting the following drawing mode on map, a thought for future development
+// // google.maps.drawing.OverlayType.CIRCLE,
+// // google.maps.drawing.OverlayType.POLYLINE,
+// // ],
+// // },
+// // });
+
+// // options for searchbox in Google Maps Places Autocomplete API
+// const options = {
+// fields: ['formatted_address', 'geometry', 'name'], // note: level of details is charged by item per retrieval, not recommended to return all fields
+// strictBounds: false,
+// types: ['establishment'], // type pf places, subject of change according to user need
+// } as google.maps.places.AutocompleteOptions;
+
+// @observer
+// export class MapBox2 extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps & Partial<GoogleMapProps>>() {
+// private _dropDisposer?: DragManager.DragDropDisposer;
+// private _disposers: { [name: string]: IReactionDisposer } = {};
+// private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
+// @observable private _overlayAnnoInfo: Opt<Doc>;
+// showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno));
+// public static LayoutString(fieldKey: string) {
+// return FieldView.LayoutString(MapBox2, fieldKey);
+// }
+// public get SidebarKey() {
+// return this.fieldKey + '_sidebar';
+// }
+// private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void);
+// @computed get inlineTextAnnotations() {
+// return this.allMapMarkers.filter(a => a.text_inlineAnnotations);
+// }
+
+// @observable private _map: google.maps.Map = null as unknown as google.maps.Map;
+// @observable private selectedPlace: Doc | undefined;
+// @observable private markerMap: { [id: string]: google.maps.Marker } = {};
+// @observable private center = navigator.geolocation ? navigator.geolocation.getCurrentPosition : defaultCenter;
+// @observable private inputRef = React.createRef<HTMLInputElement>();
+// @observable private searchMarkers: google.maps.Marker[] = [];
+// @observable private searchBox = new window.google.maps.places.Autocomplete(this.inputRef.current!, options);
+// @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+// @computed get allSidebarDocs() {
+// return DocListCast(this.dataDoc[this.SidebarKey]);
+// }
+// @computed get allMapMarkers() {
+// return DocListCast(this.dataDoc[this.annotationKey]);
+// }
+// @observable private toggleAddMarker = false;
+
+// @observable _showSidebar = false;
+// @computed get SidebarShown() {
+// return this._showSidebar || this.layoutDoc._layout_showSidebar ? true : false;
+// }
+
+// static _canAnnotate = true;
+// static _hadSelection: boolean = false;
+// private _sidebarRef = React.createRef<SidebarAnnos>();
+// private _ref: React.RefObject<HTMLDivElement> = React.createRef();
+
+// componentDidMount() {
+// this.props.setContentView?.(this);
+// }
+
+// @action
+// private setSearchBox = (searchBox: any) => {
+// this.searchBox = searchBox;
+// };
+
+// // iterate allMarkers to size, center, and zoom map to contain all markers
+// private fitBounds = (map: google.maps.Map) => {
+// const curBounds = map.getBounds() ?? new window.google.maps.LatLngBounds();
+// const isFitting = this.allMapMarkers.reduce((fits, place) => fits && curBounds?.contains({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), true as boolean);
+// !isFitting && map.fitBounds(this.allMapMarkers.reduce((bounds, place) => bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), new window.google.maps.LatLngBounds()));
+// };
+
+// /**
+// * Custom control for add marker button
+// * @param controlDiv
+// * @param map
+// */
+// private CenterControl = () => {
+// const controlDiv = document.createElement('div');
+// controlDiv.className = 'MapBox2-addMarker';
+// // Set CSS for the control border.
+// const controlUI = document.createElement('div');
+// controlUI.style.backgroundColor = '#fff';
+// controlUI.style.borderRadius = '3px';
+// controlUI.style.cursor = 'pointer';
+// controlUI.style.marginTop = '10px';
+// controlUI.style.borderRadius = '4px';
+// controlUI.style.marginBottom = '22px';
+// controlUI.style.textAlign = 'center';
+// controlUI.style.position = 'absolute';
+// controlUI.style.width = '32px';
+// controlUI.style.height = '32px';
+// controlUI.title = 'Click to toggle marker mode. In marker mode, click on map to place a marker.';
+
+// const plIcon = document.createElement('img');
+// plIcon.src = 'https://cdn4.iconfinder.com/data/icons/wirecons-free-vector-icons/32/add-256.png';
+// plIcon.style.color = 'rgb(25,25,25)';
+// plIcon.style.fontFamily = 'Roboto,Arial,sans-serif';
+// plIcon.style.fontSize = '16px';
+// plIcon.style.lineHeight = '32px';
+// plIcon.style.left = '18';
+// plIcon.style.top = '15';
+// plIcon.style.position = 'absolute';
+// plIcon.width = 14;
+// plIcon.height = 14;
+// plIcon.innerHTML = 'Add';
+// controlUI.appendChild(plIcon);
+
+// // Set CSS for the control interior.
+// const markerIcon = document.createElement('img');
+// markerIcon.src = 'https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678111-map-marker-1024.png';
+// markerIcon.style.color = 'rgb(25,25,25)';
+// markerIcon.style.fontFamily = 'Roboto,Arial,sans-serif';
+// markerIcon.style.fontSize = '16px';
+// markerIcon.style.lineHeight = '32px';
+// markerIcon.style.left = '-2';
+// markerIcon.style.top = '1';
+// markerIcon.width = 30;
+// markerIcon.height = 30;
+// markerIcon.style.position = 'absolute';
+// markerIcon.innerHTML = 'Add';
+// controlUI.appendChild(markerIcon);
+
+// // Setup the click event listeners
+// controlUI.addEventListener('click', () => {
+// if (this.toggleAddMarker === true) {
+// this.toggleAddMarker = false;
+// console.log('add marker button status:' + this.toggleAddMarker);
+// controlUI.style.backgroundColor = '#fff';
+// markerIcon.style.color = 'rgb(25,25,25)';
+// } else {
+// this.toggleAddMarker = true;
+// console.log('add marker button status:' + this.toggleAddMarker);
+// controlUI.style.backgroundColor = '#4476f7';
+// markerIcon.style.color = 'rgb(255,255,255)';
+// }
+// });
+// controlDiv.appendChild(controlUI);
+// return controlDiv;
+// };
+
+// /**
+// * Place the marker on google maps & store the empty marker as a MapMarker Document in allMarkers list
+// * @param position - the LatLng position where the marker is placed
+// * @param map
+// */
+// @action
+// private placeMarker = (position: google.maps.LatLng, map: google.maps.Map) => {
+// const marker = new google.maps.Marker({
+// position: position,
+// map: map,
+// });
+// map.panTo(position);
+// const mapMarker = Docs.Create.PushpinDocument(NumCast(position.lat()), NumCast(position.lng()), false, [], {});
+// this.addDocument(mapMarker, this.annotationKey);
+// };
+
+// _loadPending = true;
+// /**
+// * store a reference to google map instance
+// * setup the drawing manager on the top right corner of map
+// * fit map bounds to contain all markers
+// * @param map
+// */
+// @action
+// private loadHandler = (map: google.maps.Map) => {
+// this._map = map;
+// this._loadPending = true;
+// const centerControlDiv = this.CenterControl();
+// map.controls[google.maps.ControlPosition.TOP_RIGHT].push(centerControlDiv);
+// //drawingManager.setMap(map);
+// // if (navigator.geolocation) {
+// // navigator.geolocation.getCurrentPosition(
+// // (position: Position) => {
+// // const pos = {
+// // lat: position.coords.latitude,
+// // lng: position.coords.longitude,
+// // };
+// // this._map.setCenter(pos);
+// // }
+// // );
+// // } else {
+// // alert("Your geolocation is not supported by browser.")
+// // };
+// map.setZoom(NumCast(this.dataDoc.map_zoom, 2.5));
+// map.setCenter(new google.maps.LatLng(NumCast(this.dataDoc.mapLat), NumCast(this.dataDoc.mapLng)));
+// setTimeout(() => {
+// if (this._loadPending && this._map.getBounds()) {
+// this._loadPending = false;
+// this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
+// }
+// }, 250);
+// // listener to addmarker event
+// this._map.addListener('click', (e: MouseEvent) => {
+// if (this.toggleAddMarker === true) {
+// this.placeMarker((e as any).latLng, map);
+// }
+// });
+// };
+
+// @action
+// centered = () => {
+// if (this._loadPending && this._map.getBounds()) {
+// this._loadPending = false;
+// this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
+// }
+// this.dataDoc.mapLat = this._map.getCenter()?.lat();
+// this.dataDoc.mapLng = this._map.getCenter()?.lng();
+// };
+
+// @action
+// zoomChanged = () => {
+// if (this._loadPending && this._map.getBounds()) {
+// this._loadPending = false;
+// this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map);
+// }
+// this.dataDoc.map_zoom = this._map.getZoom();
+// };
+
+// /**
+// * Load and render all map markers
+// * @param marker
+// * @param place
+// */
+// @action
+// private markerLoadHandler = (marker: google.maps.Marker, place: Doc) => {
+// place[Id] ? (this.markerMap[place[Id]] = marker) : null;
+// };
+
+// /**
+// * on clicking the map marker, set the selected place to the marker document & set infowindowopen to be true
+// * @param e
+// * @param place
+// */
+// @action
+// private markerClickHandler = (e: google.maps.MapMouseEvent, place: Doc) => {
+// // set which place was clicked
+// this.selectedPlace = place;
+// place.infoWindowOpen = true;
+// };
+
+// /**
+// * Called when dragging documents into map sidebar or directly into infowindow; to create a map marker, ref to MapMarkerDocument in Documents.ts
+// * @param doc
+// * @param sidebarKey
+// * @returns
+// */
+// sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
+// console.log('print all sidebar Docs');
+// if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
+// const docs = doc instanceof Doc ? [doc] : doc;
+// docs.forEach(doc => {
+// if (doc.lat !== undefined && doc.lng !== undefined) {
+// const existingMarker = this.allMapMarkers.find(marker => marker.lat === doc.lat && marker.lng === doc.lng);
+// if (existingMarker) {
+// Doc.AddDocToList(existingMarker, 'data', doc);
+// } else {
+// const marker = Docs.Create.PushpinDocument(NumCast(doc.lat), NumCast(doc.lng), false, [doc], {});
+// this.addDocument(marker, this.annotationKey);
+// }
+// }
+// }); //add to annotation list
+
+// return this.addDocument(doc, sidebarKey); // add to sidebar list
+// };
+
+// /**
+// * Removing documents from the sidebar
+// * @param doc
+// * @param sidebarKey
+// * @returns
+// */
+// sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
+// if (this.layoutDoc._layout_showSidebar) this.toggleSidebar();
+// const docs = doc instanceof Doc ? [doc] : doc;
+// return this.removeDocument(doc, sidebarKey);
+// };
+
+// /**
+// * Toggle sidebar onclick the tiny comment button on the top right corner
+// * @param e
+// */
+// sidebarBtnDown = (e: React.PointerEvent) => {
+// setupMoveUpEvents(
+// this,
+// e,
+// (e, down, delta) =>
+// runInAction(() => {
+// const localDelta = this.props
+// .ScreenToLocalTransform()
+// .scale(this.props.NativeDimScaling?.() || 1)
+// .transformDirection(delta[0], delta[1]);
+// const fullWidth = NumCast(this.layoutDoc._width);
+// const mapWidth = fullWidth - this.sidebarWidth();
+// if (this.sidebarWidth() + localDelta[0] > 0) {
+// this._showSidebar = true;
+// this.layoutDoc._width = fullWidth + localDelta[0];
+// this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%';
+// } else {
+// this._showSidebar = false;
+// this.layoutDoc._width = mapWidth;
+// this.layoutDoc._layout_sidebarWidthPercent = '0%';
+// }
+// return false;
+// }),
+// emptyFunction,
+// () => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar map')
+// );
+// };
+
+// sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
+// @computed get layout_sidebarWidthPercent() {
+// return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
+// }
+// @computed get sidebarColor() {
+// return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
+// }
+
+// /**
+// * function that reads the place inputed from searchbox, then zoom in on the location that's been autocompleted;
+// * add a customized temporary marker on the map
+// */
+// @action
+// private handlePlaceChanged = () => {
+// const place = this.searchBox.getPlace();
+
+// if (!place.geometry || !place.geometry.location) {
+// // user entered the name of a place that wasn't suggested & pressed the enter key, or place details request failed
+// window.alert("No details available for input: '" + place.name + "'");
+// return;
+// }
+
+// // zoom in on the location of the search result
+// if (place.geometry.viewport) {
+// this._map.fitBounds(place.geometry.viewport);
+// } else {
+// this._map.setCenter(place.geometry.location);
+// this._map.setZoom(17);
+// }
+
+// // customize icon => customized icon for the nature of the location selected
+// const icon = {
+// url: place.icon as string,
+// size: new google.maps.Size(71, 71),
+// origin: new google.maps.Point(0, 0),
+// anchor: new google.maps.Point(17, 34),
+// scaledSize: new google.maps.Size(25, 25),
+// };
+
+// // put temporary cutomized marker on searched location
+// this.searchMarkers.forEach(marker => {
+// marker.setMap(null);
+// });
+// this.searchMarkers = [];
+// this.searchMarkers.push(
+// new window.google.maps.Marker({
+// map: this._map,
+// icon,
+// title: place.name,
+// position: place.geometry.location,
+// })
+// );
+// };
+
+// /**
+// * Handles toggle of sidebar on click the little comment button
+// */
+// @computed get sidebarHandle() {
+// return (
+// <div
+// className="MapBox2-overlayButton-sidebar"
+// key="sidebar"
+// title="Toggle Sidebar"
+// style={{
+// display: !this.props.isContentActive() ? 'none' : undefined,
+// top: StrCast(this.layoutDoc._layout_showTitle) === 'title' ? 20 : 5,
+// backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
+// }}
+// onPointerDown={this.sidebarBtnDown}>
+// <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={'comment-alt'} size="sm" />
+// </div>
+// );
+// }
+
+// // TODO: Adding highlight box layer to Maps
+// @action
+// toggleSidebar = () => {
+// //1.2 * w * ? = .2 * w .2/1.2
+// const prevWidth = this.sidebarWidth();
+// this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%';
+// this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
+// };
+
+// sidebarDown = (e: React.PointerEvent) => {
+// setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), true);
+// };
+// sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
+// const bounds = this._ref.current!.getBoundingClientRect();
+// this.layoutDoc._layout_sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%';
+// this.layoutDoc._layout_showSidebar = this.layoutDoc._layout_sidebarWidthPercent !== '0%';
+// e.preventDefault();
+// return false;
+// };
+
+// setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func);
+
+// addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => {
+// return this.addDocument(doc, annotationKey);
+// };
+
+// pointerEvents = () => {
+// return this.props.isContentActive() === false ? 'none' : this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none';
+// };
+// @computed get annotationLayer() {
+// return (
+// <div className="MapBox2-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer}>
+// {this.inlineTextAnnotations
+// .sort((a, b) => NumCast(a.y) - NumCast(b.y))
+// .map(anno => (
+// <Annotation key={`${anno[Id]}-annotation`} {...this.props} fieldKey={this.annotationKey} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} />
+// ))}
+// </div>
+// );
+// }
+
+// getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.Document;
+
+// /**
+// * render contents in allMapMarkers (e.g. images with exifData) into google maps as map marker
+// * @returns
+// */
+// private renderMarkers = () => {
+// return this.allMapMarkers.map(place => (
+// <Marker key={place[Id]} position={{ lat: NumCast(place.lat), lng: NumCast(place.lng) }} onLoad={marker => this.markerLoadHandler(marker, place)} onClick={(e: google.maps.MapMouseEvent) => this.markerClickHandler(e, place)} />
+// ));
+// };
+
+// // TODO: auto center on select a document in the sidebar
+// private handleMapCenter = (map: google.maps.Map) => {
+// // console.log("print the selected views in selectionManager:")
+// // if (SelectionManager.Views().lastElement()) {
+// // console.log(SelectionManager.Views().lastElement());
+// // }
+// };
+
+// panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth();
+// panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
+// scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop));
+// transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter];
+// opaqueFilter = () => [...this.props.childFilters(), Utils.OpaqueBackgroundFilter];
+// infoWidth = () => this.props.PanelWidth() / 5;
+// infoHeight = () => this.props.PanelHeight() / 5;
+// anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
+// savedAnnotations = () => this._savedAnnotations;
+
+// get MicrosoftMaps() {
+// return (window as any).Microsoft.Maps;
+// }
+// render() {
+// const renderAnnotations = (childFilters?: () => string[]) => null;
+// return (
+// <div className="MapBox2" ref={this._ref}>
+// <div
+// className="MapBox2-wrapper"
+// onWheel={e => e.stopPropagation()}
+// onPointerDown={async e => {
+// e.button === 0 && !e.ctrlKey && e.stopPropagation();
+// }}
+// style={{ width: `calc(100% - ${this.layout_sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
+// <div style={{ mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>
+// {renderAnnotations(this.opaqueFilter)}
+// {SnappingManager.GetIsDragging() ? null : renderAnnotations()}
+// {this.annotationLayer}
+
+// <div>
+// <GoogleMap mapContainerStyle={mapContainerStyle} onZoomChanged={this.zoomChanged} onCenterChanged={this.centered} onLoad={this.loadHandler} options={mapOptions}>
+// <Autocomplete onLoad={this.setSearchBox} onPlaceChanged={this.handlePlaceChanged}>
+// <input className="MapBox2-input" ref={this.inputRef} type="text" onKeyDown={e => e.stopPropagation()} placeholder="Enter location" />
+// </Autocomplete>
+
+// {this.renderMarkers()}
+// {this.allMapMarkers
+// .filter(marker => marker.infoWindowOpen)
+// .map(marker => (
+// <MapBoxInfoWindow
+// key={marker[Id]}
+// {...this.props}
+// setContentView={emptyFunction}
+// place={marker}
+// markerMap={this.markerMap}
+// PanelWidth={this.infoWidth}
+// PanelHeight={this.infoHeight}
+// moveDocument={this.moveDocument}
+// isAnyChildContentActive={this.isAnyChildContentActive}
+// whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+// />
+// ))}
+// {/* {this.handleMapCenter(this._map)} */}
+// </GoogleMap>
+// </div>
+// </div>
+// {/* </LoadScript > */}
+// <div className="MapBox2-sidebar" style={{ width: `${this.layout_sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+// <SidebarAnnos
+// ref={this._sidebarRef}
+// {...this.props}
+// fieldKey={this.fieldKey}
+// Document={this.Document}
+// layoutDoc={this.layoutDoc}
+// dataDoc={this.dataDoc}
+// usePanelWidth={true}
+// showSidebar={this.SidebarShown}
+// nativeWidth={NumCast(this.layoutDoc._nativeWidth)}
+// whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+// PanelWidth={this.sidebarWidth}
+// sidebarAddDocument={this.sidebarAddDocument}
+// moveDocument={this.moveDocument}
+// removeDocument={this.sidebarRemoveDocument}
+// />
+// </div>
+// {this.sidebarHandle}
+// </div>
+// );
+// }
+// }
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index 415a9d776..a9c6ba22c 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -1,95 +1,95 @@
-import { InfoWindow } from '@react-google-maps/api';
-import { action } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc } from '../../../../fields/Doc';
-import { Id } from '../../../../fields/FieldSymbols';
-import { emptyFunction, returnAll, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents } from '../../../../Utils';
-import { Docs } from '../../../documents/Documents';
-import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
-import { CollectionNoteTakingView } from '../../collections/CollectionNoteTakingView';
-import { CollectionStackingView } from '../../collections/CollectionStackingView';
-import { ViewBoxAnnotatableProps } from '../../DocComponent';
-import { FieldViewProps } from '../FieldView';
-import { FormattedTextBox } from '../formattedText/FormattedTextBox';
-import './MapBox.scss';
+// import { InfoWindow } from '@react-google-maps/api';
+// import { action } from 'mobx';
+// import { observer } from 'mobx-react';
+// import * as React from 'react';
+// import { Doc } from '../../../../fields/Doc';
+// import { Id } from '../../../../fields/FieldSymbols';
+// import { emptyFunction, returnAll, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents } from '../../../../Utils';
+// import { Docs } from '../../../documents/Documents';
+// import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
+// import { CollectionNoteTakingView } from '../../collections/CollectionNoteTakingView';
+// import { CollectionStackingView } from '../../collections/CollectionStackingView';
+// import { ViewBoxAnnotatableProps } from '../../DocComponent';
+// import { FieldViewProps } from '../FieldView';
+// import { FormattedTextBox } from '../formattedText/FormattedTextBox';
+// import './MapBox.scss';
-interface MapBoxInfoWindowProps {
- place: Doc;
- renderDepth: number;
- markerMap: { [id: string]: google.maps.Marker };
- isAnyChildContentActive: () => boolean;
-}
-@observer
-export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & ViewBoxAnnotatableProps & FieldViewProps> {
- @action
- private handleInfoWindowClose = () => {
- if (this.props.place.infoWindowOpen) {
- this.props.place.infoWindowOpen = false;
- }
- this.props.place.infoWindowOpen = false;
- };
+// interface MapBoxInfoWindowProps {
+// place: Doc;
+// renderDepth: number;
+// markerMap: { [id: string]: google.maps.Marker };
+// isAnyChildContentActive: () => boolean;
+// }
+// @observer
+// export class MapBoxInfoWindow extends React.Component<MapBoxInfoWindowProps & ViewBoxAnnotatableProps & FieldViewProps> {
+// @action
+// private handleInfoWindowClose = () => {
+// if (this.props.place.infoWindowOpen) {
+// this.props.place.infoWindowOpen = false;
+// }
+// this.props.place.infoWindowOpen = false;
+// };
- addNoteClick = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => {
- const newDoc = Docs.Create.TextDocument('Note', { _layout_autoHeight: true });
- FormattedTextBox.SetSelectOnLoad(newDoc); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
- Doc.AddDocToList(this.props.place, 'data', newDoc);
- this._stack?.scrollToBottom();
- e.stopPropagation();
- e.preventDefault();
- });
- };
+// addNoteClick = (e: React.PointerEvent) => {
+// setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => {
+// const newDoc = Docs.Create.TextDocument('Note', { _layout_autoHeight: true });
+// FormattedTextBox.SetSelectOnLoad(newDoc); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
+// Doc.AddDocToList(this.props.place, 'data', newDoc);
+// this._stack?.scrollToBottom();
+// e.stopPropagation();
+// e.preventDefault();
+// });
+// };
- _stack: CollectionStackingView | CollectionNoteTakingView | null | undefined;
- childLayoutFitWidth = (doc: Doc) => doc.type === DocumentType.RTF;
- addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.AddDocToList(this.props.place, 'data', d), true as boolean);
- removeDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.RemoveDocFromList(this.props.place, 'data', d), true as boolean);
- render() {
- return (
- <InfoWindow
- // anchor={this.props.markerMap[this.props.place[Id]]}
- onCloseClick={this.handleInfoWindowClose}>
- <div className="mapbox-infowindow">
- <div style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}>
- <CollectionStackingView
- ref={r => (this._stack = r)}
- {...this.props}
- setContentView={emptyFunction}
- Document={this.props.place}
- TemplateDataDocument={undefined}
- fieldKey="data"
- NativeWidth={returnZero}
- NativeHeight={returnZero}
- childFilters={returnEmptyFilter}
- setHeight={emptyFunction}
- isAnnotationOverlay={false}
- select={emptyFunction}
- NativeDimScaling={returnOne}
- isContentActive={returnTrue}
- chromeHidden={true}
- childHideResizeHandles={true}
- childHideDecorationTitle={true}
- childLayoutFitWidth={this.childLayoutFitWidth}
- // childDocumentsActive={returnFalse}
- removeDocument={this.removeDoc}
- addDocument={this.addDoc}
- renderDepth={this.props.renderDepth + 1}
- type_collection={CollectionViewType.Stacking}
- pointerEvents={returnAll}
- />
- </div>
- <hr />
- <div
- onPointerDown={this.addNoteClick}
- onClick={e => {
- e.stopPropagation();
- e.preventDefault();
- }}>
- Add Note
- </div>
- </div>
- </InfoWindow>
- );
- }
-}
+// _stack: CollectionStackingView | CollectionNoteTakingView | null | undefined;
+// childLayoutFitWidth = (doc: Doc) => doc.type === DocumentType.RTF;
+// addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.AddDocToList(this.props.place, 'data', d), true as boolean);
+// removeDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.RemoveDocFromList(this.props.place, 'data', d), true as boolean);
+// render() {
+// return (
+// <InfoWindow
+// // anchor={this.props.markerMap[this.props.place[Id]]}
+// onCloseClick={this.handleInfoWindowClose}>
+// <div className="mapbox-infowindow">
+// <div style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}>
+// <CollectionStackingView
+// ref={r => (this._stack = r)}
+// {...this.props}
+// setContentView={emptyFunction}
+// Document={this.props.place}
+// TemplateDataDocument={undefined}
+// fieldKey="data"
+// NativeWidth={returnZero}
+// NativeHeight={returnZero}
+// childFilters={returnEmptyFilter}
+// setHeight={emptyFunction}
+// isAnnotationOverlay={false}
+// select={emptyFunction}
+// NativeDimScaling={returnOne}
+// isContentActive={returnTrue}
+// chromeHidden={true}
+// childHideResizeHandles={true}
+// childHideDecorationTitle={true}
+// childLayoutFitWidth={this.childLayoutFitWidth}
+// // childDocumentsActive={returnFalse}
+// removeDocument={this.removeDoc}
+// addDocument={this.addDoc}
+// renderDepth={this.props.renderDepth + 1}
+// type_collection={CollectionViewType.Stacking}
+// pointerEvents={returnAll}
+// />
+// </div>
+// <hr />
+// <div
+// onPointerDown={this.addNoteClick}
+// onClick={e => {
+// e.stopPropagation();
+// e.preventDefault();
+// }}>
+// Add Note
+// </div>
+// </div>
+// </InfoWindow>
+// );
+// }
+// }
diff --git a/src/client/views/nodes/formattedText/EquationEditor.tsx b/src/client/views/nodes/formattedText/EquationEditor.tsx
new file mode 100644
index 000000000..bde6c1315
--- /dev/null
+++ b/src/client/views/nodes/formattedText/EquationEditor.tsx
@@ -0,0 +1,87 @@
+import React, { Component, createRef } from 'react';
+
+// Import JQuery, required for the functioning of the equation editor
+import $ from 'jquery';
+
+// Import the styles from the Mathquill editor
+import 'mathquill/build/mathquill.css';
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
+// @ts-ignore
+window.jQuery = $;
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
+// @ts-ignore
+require('mathquill/build/mathquill');
+
+type EquationEditorProps = {
+ onChange(latex: string): void;
+ value: string;
+ spaceBehavesLikeTab?: boolean;
+ autoCommands: string;
+ autoOperatorNames: string;
+ onEnter?(): void;
+};
+
+/**
+ * @typedef {EquationEditorProps} props
+ * @prop {Function} onChange Triggered when content of the equation editor changes
+ * @prop {string} value Content of the equation handler
+ * @prop {boolean}[false] spaceBehavesLikeTab Whether spacebar should simulate tab behavior
+ * @prop {string} autoCommands List of commands for which you only have to type the name of the
+ * command with a \ in front of it. Examples: pi theta rho sum
+ * @prop {string} autoOperatorNames List of operators for which you only have to type the name of the
+ * operator with a \ in front of it. Examples: sin cos tan
+ * @prop {Function} onEnter Triggered when enter is pressed in the equation editor
+ * @extends {Component<EquationEditorProps>}
+ */
+class EquationEditor extends Component<EquationEditorProps> {
+ element: any;
+ mathField: any;
+ ignoreEditEvents: number;
+
+ // Element needs to be in the class format and thus requires a constructor. The steps that are run
+ // in the constructor is to make sure that React can succesfully communicate with the equation
+ // editor.
+ constructor(props: EquationEditorProps) {
+ super(props);
+
+ this.element = createRef();
+ this.mathField = null;
+
+ // MathJax apparently fire 2 edit events on startup.
+ this.ignoreEditEvents = 2;
+ }
+
+ componentDidMount() {
+ const { onChange, value, spaceBehavesLikeTab, autoCommands, autoOperatorNames, onEnter } = this.props;
+
+ const config = {
+ handlers: {
+ edit: () => {
+ if (this.ignoreEditEvents > 0) {
+ this.ignoreEditEvents -= 1;
+ return;
+ }
+ if (this.mathField.latex() !== value) {
+ onChange(this.mathField.latex());
+ }
+ },
+ enter: onEnter,
+ },
+ spaceBehavesLikeTab,
+ autoCommands,
+ autoOperatorNames,
+ };
+
+ // @ts-ignore
+ this.mathField = (MathQuill as any).MathField(this.element.current, config);
+ this.mathField.latex(value || '');
+ }
+
+ render() {
+ return <span ref={this.element} style={{ border: '0px', boxShadow: 'None' }} />;
+ }
+}
+
+export default EquationEditor;
diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx
index 75238a6ce..5ee5d25c3 100644
--- a/src/client/views/nodes/formattedText/EquationView.tsx
+++ b/src/client/views/nodes/formattedText/EquationView.tsx
@@ -1,4 +1,4 @@
-import EquationEditor from 'equation-editor-react';
+import EquationEditor from './EquationEditor';
import { IReactionDisposer, trace } from 'mobx';
import { observer } from 'mobx-react';
import { TextSelection } from 'prosemirror-state';
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 0f9dd6f8b..4f8e8769a 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -70,7 +70,7 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu';
import { RichTextRules } from './RichTextRules';
import { schema } from './schema_rts';
import { SummaryView } from './SummaryView';
-import * as applyDevTools from 'prosemirror-dev-tools';
+// import * as applyDevTools from 'prosemirror-dev-tools';
import * as React from 'react';
export const GoogleRef = 'googleDocId';
type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void;