aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanley Yip <stanley_yip@brown.edu>2020-01-20 13:45:31 -0500
committerStanley Yip <stanley_yip@brown.edu>2020-01-20 13:45:31 -0500
commit87bdb7c7eafa1e91e371c9d88b8dd36197f497d3 (patch)
tree65191f06e01e9eab74ecd40c20f3476e532d061c
parenta61dfaab422886733a727eebe80b619230d59684 (diff)
parentdf61d40f92a29f948d9f513fb9f50349f16500ee (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into pen
-rw-r--r--package-lock.json430
-rw-r--r--package.json3
-rw-r--r--src/client/documents/Documents.ts48
-rw-r--r--src/client/util/DropConverter.ts10
-rw-r--r--src/client/views/TemplateMenu.tsx4
-rw-r--r--src/client/views/collections/CollectionMulticolumnView.scss23
-rw-r--r--src/client/views/collections/CollectionPivotView.tsx4
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx12
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx31
-rw-r--r--src/client/views/collections/CollectionView.tsx21
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss33
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx (renamed from src/client/views/collections/CollectionMulticolumnView.tsx)238
-rw-r--r--src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx116
-rw-r--r--src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx56
-rw-r--r--src/client/views/nodes/DocumentView.tsx15
-rw-r--r--src/client/views/nodes/FieldView.tsx2
-rw-r--r--src/scraping/buxton/node_scraper.ts57
-rw-r--r--src/scraping/buxton/scraper.py67
-rw-r--r--src/scraping/buxton/source/Bill_Notes_NB75D.docxbin0 -> 27696302 bytes
19 files changed, 787 insertions, 383 deletions
diff --git a/package-lock.json b/package-lock.json
index 82c310a14..0157e0c99 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1061,6 +1061,11 @@
}
}
},
+ "@types/word-extractor": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@types/word-extractor/-/word-extractor-0.3.0.tgz",
+ "integrity": "sha512-XcVsLXMpPT6Lv4Qvsc2yPoWg3zPVKEIyQ21eQ1ka58zZjtd7vUZ2kx0KydRbsNRNGopEIiwlemGzgo46dytR2Q=="
+ },
"@types/youtube": {
"version": "0.0.38",
"resolved": "https://registry.npmjs.org/@types/youtube/-/youtube-0.0.38.tgz",
@@ -1504,7 +1509,7 @@
"resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz",
"integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==",
"requires": {
- "readable-stream": "3.4.0"
+ "readable-stream": "^3.0.1"
}
},
"readable-stream": {
@@ -1512,9 +1517,9 @@
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"requires": {
- "inherits": "2.0.3",
- "string_decoder": "1.1.1",
- "util-deprecate": "1.0.2"
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
}
},
"tar-stream": {
@@ -1522,11 +1527,11 @@
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz",
"integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==",
"requires": {
- "bl": "3.0.0",
- "end-of-stream": "1.4.1",
- "fs-constants": "1.0.0",
- "inherits": "2.0.3",
- "readable-stream": "3.4.0"
+ "bl": "^3.0.0",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
}
}
}
@@ -4220,6 +4225,11 @@
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
},
+ "duplexer": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
+ "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E="
+ },
"duplexer3": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
@@ -4617,6 +4627,20 @@
"resolved": "https://registry.npmjs.org/ev-emitter/-/ev-emitter-1.1.1.tgz",
"integrity": "sha512-ipiDYhdQSCZ4hSbX4rMW+XzNKMD1prg/sTvoVmSLkuQ1MVlwjJQQA+sW8tMYR3BLUr9KjodFV4pvzunvRhd33Q=="
},
+ "event-stream": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz",
+ "integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==",
+ "requires": {
+ "duplexer": "^0.1.1",
+ "from": "^0.1.7",
+ "map-stream": "0.0.7",
+ "pause-stream": "^0.0.11",
+ "split": "^1.0.1",
+ "stream-combiner": "^0.2.2",
+ "through": "^2.3.8"
+ }
+ },
"event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
@@ -5143,7 +5167,7 @@
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
- "ms": "2.1.2"
+ "ms": "^2.1.1"
}
},
"ms": {
@@ -5207,7 +5231,7 @@
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
- "color-convert": "1.9.3"
+ "color-convert": "^1.9.0"
}
},
"chalk": {
@@ -5216,9 +5240,9 @@
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
- "ansi-styles": "3.2.1",
- "escape-string-regexp": "1.0.5",
- "supports-color": "5.5.0"
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
}
},
"supports-color": {
@@ -5227,7 +5251,7 @@
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
- "has-flag": "3.0.0"
+ "has-flag": "^3.0.0"
}
}
}
@@ -5265,6 +5289,11 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
+ "from": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
+ "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4="
+ },
"from2": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
@@ -5372,7 +5401,7 @@
"bundled": true,
"optional": true,
"requires": {
- "balanced-match": "1.0.0",
+ "balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
@@ -5406,7 +5435,7 @@
"bundled": true,
"optional": true,
"requires": {
- "ms": "2.1.2"
+ "ms": "^2.1.1"
}
},
"deep-extend": {
@@ -5475,7 +5504,7 @@
"bundled": true,
"optional": true,
"requires": {
- "safer-buffer": "2.1.2"
+ "safer-buffer": ">= 2.1.2 < 3"
}
},
"ignore-walk": {
@@ -5483,7 +5512,7 @@
"bundled": true,
"optional": true,
"requires": {
- "minimatch": "3.0.4"
+ "minimatch": "^3.0.4"
}
},
"inflight": {
@@ -5510,7 +5539,7 @@
"bundled": true,
"optional": true,
"requires": {
- "number-is-nan": "1.0.1"
+ "number-is-nan": "^1.0.0"
}
},
"isarray": {
@@ -5523,7 +5552,7 @@
"bundled": true,
"optional": true,
"requires": {
- "brace-expansion": "1.1.11"
+ "brace-expansion": "^1.1.7"
}
},
"minimist": {
@@ -5593,8 +5622,8 @@
"bundled": true,
"optional": true,
"requires": {
- "abbrev": "1.1.1",
- "osenv": "0.1.5"
+ "abbrev": "1",
+ "osenv": "^0.1.4"
}
},
"npm-bundled": {
@@ -5602,7 +5631,7 @@
"bundled": true,
"optional": true,
"requires": {
- "npm-normalize-package-bin": "1.0.1"
+ "npm-normalize-package-bin": "^1.0.1"
}
},
"npm-normalize-package-bin": {
@@ -5615,8 +5644,8 @@
"bundled": true,
"optional": true,
"requires": {
- "ignore-walk": "3.0.3",
- "npm-bundled": "1.1.1"
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
}
},
"npmlog": {
@@ -5663,8 +5692,8 @@
"bundled": true,
"optional": true,
"requires": {
- "os-homedir": "1.0.2",
- "os-tmpdir": "1.0.2"
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
}
},
"path-is-absolute": {
@@ -7324,9 +7353,9 @@
"integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
"dev": true,
"requires": {
- "ip-regex": "2.1.0",
- "psl": "1.2.0",
- "punycode": "2.1.1"
+ "ip-regex": "^2.1.0",
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
}
}
}
@@ -7906,6 +7935,11 @@
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
"integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0="
},
+ "map-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz",
+ "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg="
+ },
"map-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
@@ -8677,6 +8711,11 @@
}
}
},
+ "node-stream-zip": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.9.1.tgz",
+ "integrity": "sha512-7/Xs9gkuYF0WBimz5OrSc6UVKLDTxvBG2yLGtEK8PSx94d86o/6iQLvIe/140ATz35JDqHKWIxh3GcA3u5hB0w=="
+ },
"nodemailer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-5.1.1.tgz",
@@ -8704,7 +8743,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
- "ms": "2.1.2"
+ "ms": "^2.1.1"
}
},
"ms": {
@@ -8722,7 +8761,7 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
- "has-flag": "3.0.0"
+ "has-flag": "^3.0.0"
}
}
}
@@ -12387,6 +12426,14 @@
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
},
+ "pause-stream": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+ "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
+ "requires": {
+ "through": "~2.3"
+ }
+ },
"pbkdf2": {
"version": "3.0.17",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
@@ -13406,7 +13453,7 @@
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"requires": {
- "loose-envify": "1.4.0"
+ "loose-envify": "^1.0.0"
}
}
}
@@ -13599,7 +13646,7 @@
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"requires": {
- "loose-envify": "1.4.0"
+ "loose-envify": "^1.0.0"
}
}
}
@@ -15054,7 +15101,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
- "ms": "2.1.2"
+ "ms": "^2.1.1"
}
},
"ms": {
@@ -15205,7 +15252,7 @@
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
- "ms": "2.1.2"
+ "ms": "^2.1.1"
}
},
"faye-websocket": {
@@ -15214,7 +15261,7 @@
"integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
"dev": true,
"requires": {
- "websocket-driver": "0.7.3"
+ "websocket-driver": ">=0.5.1"
}
},
"ms": {
@@ -15344,7 +15391,7 @@
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
- "ms": "2.1.2"
+ "ms": "^2.1.1"
}
},
"ms": {
@@ -15397,6 +15444,14 @@
}
}
},
+ "split": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+ "requires": {
+ "through": "2"
+ }
+ },
"split-on-first": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
@@ -15510,6 +15565,18 @@
"requires": {
"inherits": "~2.0.1",
"readable-stream": "^2.0.2"
+<<<<<<< HEAD
+=======
+ }
+ },
+ "stream-combiner": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz",
+ "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=",
+ "requires": {
+ "duplexer": "~0.1.1",
+ "through": "~2.3.4"
+>>>>>>> df61d40f92a29f948d9f513fb9f50349f16500ee
}
},
"stream-each": {
@@ -15838,9 +15905,9 @@
"integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
"dev": true,
"requires": {
- "commondir": "1.0.1",
- "make-dir": "2.1.0",
- "pkg-dir": "3.0.0"
+ "commondir": "^1.0.1",
+ "make-dir": "^2.0.0",
+ "pkg-dir": "^3.0.0"
}
},
"find-up": {
@@ -15849,7 +15916,7 @@
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
- "locate-path": "3.0.0"
+ "locate-path": "^3.0.0"
}
},
"locate-path": {
@@ -15858,8 +15925,8 @@
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"requires": {
- "p-locate": "3.0.0",
- "path-exists": "3.0.0"
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
}
},
"lru-cache": {
@@ -15868,7 +15935,7 @@
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"dev": true,
"requires": {
- "yallist": "3.0.3"
+ "yallist": "^3.0.2"
}
},
"make-dir": {
@@ -15877,8 +15944,8 @@
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
"dev": true,
"requires": {
- "pify": "4.0.1",
- "semver": "5.7.0"
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
}
},
"mississippi": {
@@ -15887,16 +15954,16 @@
"integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
"dev": true,
"requires": {
- "concat-stream": "1.6.2",
- "duplexify": "3.7.1",
- "end-of-stream": "1.4.1",
- "flush-write-stream": "1.1.1",
- "from2": "2.3.0",
- "parallel-transform": "1.1.0",
- "pump": "3.0.0",
- "pumpify": "1.5.1",
- "stream-each": "1.2.3",
- "through2": "2.0.5"
+ "concat-stream": "^1.5.0",
+ "duplexify": "^3.4.2",
+ "end-of-stream": "^1.1.0",
+ "flush-write-stream": "^1.0.0",
+ "from2": "^2.1.0",
+ "parallel-transform": "^1.1.0",
+ "pump": "^3.0.0",
+ "pumpify": "^1.3.3",
+ "stream-each": "^1.1.0",
+ "through2": "^2.0.0"
}
},
"p-locate": {
@@ -15905,7 +15972,7 @@
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"requires": {
- "p-limit": "2.2.2"
+ "p-limit": "^2.0.0"
}
},
"pify": {
@@ -15920,7 +15987,7 @@
"integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
"dev": true,
"requires": {
- "find-up": "3.0.0"
+ "find-up": "^3.0.0"
}
},
"pump": {
@@ -15929,8 +15996,8 @@
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"requires": {
- "end-of-stream": "1.4.1",
- "once": "1.4.0"
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
}
},
"rimraf": {
@@ -15948,9 +16015,9 @@
"integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
"dev": true,
"requires": {
- "ajv": "6.10.2",
- "ajv-errors": "1.0.1",
- "ajv-keywords": "3.4.1"
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
}
},
"serialize-javascript": {
@@ -15971,7 +16038,7 @@
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
"dev": true,
"requires": {
- "figgy-pudding": "3.5.1"
+ "figgy-pudding": "^3.5.1"
}
},
"y18n": {
@@ -16268,7 +16335,7 @@
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
- "glob": "7.1.4"
+ "glob": "^7.1.3"
}
}
}
@@ -16326,7 +16393,7 @@
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
- "color-convert": "1.9.3"
+ "color-convert": "^1.9.0"
}
},
"chalk": {
@@ -16335,9 +16402,9 @@
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
- "ansi-styles": "3.2.1",
- "escape-string-regexp": "1.0.5",
- "supports-color": "5.5.0"
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
}
},
"diff": {
@@ -16352,7 +16419,7 @@
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
- "has-flag": "3.0.0"
+ "has-flag": "^3.0.0"
}
}
}
@@ -16951,9 +17018,9 @@
"integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
"dev": true,
"requires": {
- "ajv": "6.10.2",
- "ajv-errors": "1.0.1",
- "ajv-keywords": "3.4.1"
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
}
}
}
@@ -16989,7 +17056,7 @@
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
- "color-convert": "1.9.3"
+ "color-convert": "^1.9.0"
}
},
"camelcase": {
@@ -17004,9 +17071,9 @@
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
- "ansi-styles": "3.2.1",
- "escape-string-regexp": "1.0.5",
- "supports-color": "5.5.0"
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
},
"dependencies": {
"supports-color": {
@@ -17015,7 +17082,7 @@
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
- "has-flag": "3.0.0"
+ "has-flag": "^3.0.0"
}
}
}
@@ -17026,9 +17093,9 @@
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"dev": true,
"requires": {
- "string-width": "3.1.0",
- "strip-ansi": "5.2.0",
- "wrap-ansi": "5.1.0"
+ "string-width": "^3.1.0",
+ "strip-ansi": "^5.2.0",
+ "wrap-ansi": "^5.1.0"
}
},
"execa": {
@@ -17037,13 +17104,13 @@
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"dev": true,
"requires": {
- "cross-spawn": "6.0.5",
- "get-stream": "4.1.0",
- "is-stream": "1.1.0",
- "npm-run-path": "2.0.2",
- "p-finally": "1.0.0",
- "signal-exit": "3.0.2",
- "strip-eof": "1.0.0"
+ "cross-spawn": "^6.0.0",
+ "get-stream": "^4.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
}
},
"find-up": {
@@ -17052,7 +17119,7 @@
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
- "locate-path": "3.0.0"
+ "locate-path": "^3.0.0"
}
},
"get-caller-file": {
@@ -17067,7 +17134,7 @@
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"dev": true,
"requires": {
- "pump": "3.0.0"
+ "pump": "^3.0.0"
}
},
"invert-kv": {
@@ -17088,7 +17155,7 @@
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"dev": true,
"requires": {
- "invert-kv": "2.0.0"
+ "invert-kv": "^2.0.0"
}
},
"locate-path": {
@@ -17097,8 +17164,8 @@
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"requires": {
- "p-locate": "3.0.0",
- "path-exists": "3.0.0"
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
}
},
"os-locale": {
@@ -17107,9 +17174,9 @@
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"dev": true,
"requires": {
- "execa": "1.0.0",
- "lcid": "2.0.0",
- "mem": "4.3.0"
+ "execa": "^1.0.0",
+ "lcid": "^2.0.0",
+ "mem": "^4.0.0"
}
},
"p-locate": {
@@ -17118,7 +17185,7 @@
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"requires": {
- "p-limit": "2.2.2"
+ "p-limit": "^2.0.0"
}
},
"pump": {
@@ -17127,8 +17194,8 @@
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"requires": {
- "end-of-stream": "1.4.1",
- "once": "1.4.0"
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
}
},
"require-main-filename": {
@@ -17143,9 +17210,9 @@
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
"requires": {
- "emoji-regex": "7.0.3",
- "is-fullwidth-code-point": "2.0.0",
- "strip-ansi": "5.2.0"
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
}
},
"strip-ansi": {
@@ -17154,7 +17221,7 @@
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"requires": {
- "ansi-regex": "4.1.0"
+ "ansi-regex": "^4.1.0"
}
},
"supports-color": {
@@ -17163,7 +17230,7 @@
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
- "has-flag": "3.0.0"
+ "has-flag": "^3.0.0"
}
},
"which-module": {
@@ -17178,9 +17245,9 @@
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true,
"requires": {
- "ansi-styles": "3.2.1",
- "string-width": "3.1.0",
- "strip-ansi": "5.2.0"
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
}
},
"y18n": {
@@ -17195,17 +17262,17 @@
"integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==",
"dev": true,
"requires": {
- "cliui": "5.0.0",
- "find-up": "3.0.0",
- "get-caller-file": "2.0.5",
- "os-locale": "3.1.0",
- "require-directory": "2.1.1",
- "require-main-filename": "2.0.0",
- "set-blocking": "2.0.0",
- "string-width": "3.1.0",
- "which-module": "2.0.0",
- "y18n": "4.0.0",
- "yargs-parser": "13.1.1"
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "os-locale": "^3.1.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.0"
}
},
"yargs-parser": {
@@ -17214,8 +17281,8 @@
"integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
"dev": true,
"requires": {
- "camelcase": "5.3.1",
- "decamelize": "1.2.0"
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
}
}
}
@@ -17245,8 +17312,8 @@
"integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
"dev": true,
"requires": {
- "ansi-colors": "3.2.4",
- "uuid": "3.3.3"
+ "ansi-colors": "^3.0.0",
+ "uuid": "^3.3.2"
}
}
}
@@ -17310,9 +17377,9 @@
"integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
"dev": true,
"requires": {
- "string-width": "2.1.1",
- "strip-ansi": "4.0.0",
- "wrap-ansi": "2.1.0"
+ "string-width": "^2.1.1",
+ "strip-ansi": "^4.0.0",
+ "wrap-ansi": "^2.0.0"
},
"dependencies": {
"strip-ansi": {
@@ -17321,7 +17388,7 @@
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
- "ansi-regex": "3.0.0"
+ "ansi-regex": "^3.0.0"
}
}
}
@@ -17332,7 +17399,7 @@
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
- "ms": "2.1.2"
+ "ms": "^2.1.1"
}
},
"execa": {
@@ -17341,13 +17408,13 @@
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"dev": true,
"requires": {
- "cross-spawn": "6.0.5",
- "get-stream": "4.1.0",
- "is-stream": "1.1.0",
- "npm-run-path": "2.0.2",
- "p-finally": "1.0.0",
- "signal-exit": "3.0.2",
- "strip-eof": "1.0.0"
+ "cross-spawn": "^6.0.0",
+ "get-stream": "^4.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
}
},
"find-up": {
@@ -17356,7 +17423,7 @@
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
- "locate-path": "3.0.0"
+ "locate-path": "^3.0.0"
}
},
"get-stream": {
@@ -17365,7 +17432,7 @@
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"dev": true,
"requires": {
- "pump": "3.0.0"
+ "pump": "^3.0.0"
}
},
"invert-kv": {
@@ -17386,7 +17453,7 @@
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"dev": true,
"requires": {
- "invert-kv": "2.0.0"
+ "invert-kv": "^2.0.0"
}
},
"locate-path": {
@@ -17395,8 +17462,8 @@
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"requires": {
- "p-locate": "3.0.0",
- "path-exists": "3.0.0"
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
}
},
"loglevel": {
@@ -17417,9 +17484,9 @@
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"dev": true,
"requires": {
- "execa": "1.0.0",
- "lcid": "2.0.0",
- "mem": "4.3.0"
+ "execa": "^1.0.0",
+ "lcid": "^2.0.0",
+ "mem": "^4.0.0"
}
},
"p-locate": {
@@ -17428,7 +17495,7 @@
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"requires": {
- "p-limit": "2.2.2"
+ "p-limit": "^2.0.0"
}
},
"pump": {
@@ -17437,8 +17504,8 @@
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"requires": {
- "end-of-stream": "1.4.1",
- "once": "1.4.0"
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
}
},
"schema-utils": {
@@ -17447,9 +17514,9 @@
"integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
"dev": true,
"requires": {
- "ajv": "6.10.2",
- "ajv-errors": "1.0.1",
- "ajv-keywords": "3.4.1"
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
}
},
"semver": {
@@ -17464,8 +17531,8 @@
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"dev": true,
"requires": {
- "is-fullwidth-code-point": "2.0.0",
- "strip-ansi": "4.0.0"
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
},
"dependencies": {
"strip-ansi": {
@@ -17474,7 +17541,7 @@
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
- "ansi-regex": "3.0.0"
+ "ansi-regex": "^3.0.0"
}
}
}
@@ -17485,7 +17552,7 @@
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
- "has-flag": "3.0.0"
+ "has-flag": "^3.0.0"
}
},
"webpack-log": {
@@ -17494,8 +17561,8 @@
"integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
"dev": true,
"requires": {
- "ansi-colors": "3.2.4",
- "uuid": "3.3.3"
+ "ansi-colors": "^3.0.0",
+ "uuid": "^3.3.2"
}
},
"which-module": {
@@ -17519,18 +17586,18 @@
"integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
"dev": true,
"requires": {
- "cliui": "4.1.0",
- "decamelize": "1.2.0",
- "find-up": "3.0.0",
- "get-caller-file": "1.0.3",
- "os-locale": "3.1.0",
- "require-directory": "2.1.1",
- "require-main-filename": "1.0.1",
- "set-blocking": "2.0.0",
- "string-width": "2.1.1",
- "which-module": "2.0.0",
- "y18n": "3.2.1",
- "yargs-parser": "11.1.1"
+ "cliui": "^4.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^3.0.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^2.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^3.2.1 || ^4.0.0",
+ "yargs-parser": "^11.1.1"
}
},
"yargs-parser": {
@@ -17539,8 +17606,8 @@
"integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
"dev": true,
"requires": {
- "camelcase": "5.3.1",
- "decamelize": "1.2.0"
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
}
}
}
@@ -17760,6 +17827,23 @@
}
}
},
+ "word-extractor": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/word-extractor/-/word-extractor-0.3.0.tgz",
+ "integrity": "sha512-gFRsCojw2sijgoHXAa11b9K2OeEvajw4iQp89doDlseVYklR56Z22AlzDKeP1bo4N5wT/AJWptbcPQPstXVlsQ==",
+ "requires": {
+ "async": "^1.5.2",
+ "event-stream": "^3.3.4",
+ "underscore": "^1.8.3"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ }
+ }
+ },
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -18156,9 +18240,9 @@
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"requires": {
- "inherits": "2.0.3",
- "string_decoder": "1.1.1",
- "util-deprecate": "1.0.2"
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
}
}
}
diff --git a/package.json b/package.json
index be1d3a9fe..5077e7118 100644
--- a/package.json
+++ b/package.json
@@ -114,6 +114,7 @@
"@types/typescript": "^2.0.0",
"@types/uuid": "^3.4.6",
"@types/webpack": "^4.41.1",
+ "@types/word-extractor": "^0.3.0",
"@types/youtube": "0.0.38",
"adm-zip": "^0.4.13",
"archiver": "^3.1.1",
@@ -171,6 +172,7 @@
"mongodb": "^3.4.1",
"mongoose": "^5.8.4",
"node-sass": "^4.13.0",
+ "node-stream-zip": "^1.9.1",
"nodemailer": "^5.1.1",
"nodemon": "^1.19.4",
"normalize.css": "^8.0.1",
@@ -229,6 +231,7 @@
"url-loader": "^1.1.2",
"uuid": "^3.3.3",
"wikijs": "^6.0.1",
+ "word-extractor": "^0.3.0",
"words-to-numbers": "^1.5.1",
"xoauth2": "^1.2.0",
"youtube": "^0.1.0"
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 2aa848f5c..7e7b10ae8 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -19,7 +19,7 @@ import { AggregateFunction } from "../northstar/model/idea/idea";
import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss";
import { IconBox } from "../views/nodes/IconBox";
import { OmitKeys, JSONUtils } from "../../Utils";
-import { Field, Doc, Opt, DocListCastAsync } from "../../new_fields/Doc";
+import { Field, Doc, Opt, DocListCastAsync, FieldResult, DocListCast } from "../../new_fields/Doc";
import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField } from "../../new_fields/URLField";
import { HtmlField } from "../../new_fields/HtmlField";
import { List } from "../../new_fields/List";
@@ -51,6 +51,7 @@ import { DocuLinkBox } from "../views/nodes/DocuLinkBox";
import { DocumentBox } from "../views/nodes/DocumentBox";
import { InkingStroke } from "../views/InkingStroke";
import { InkField } from "../../new_fields/InkField";
+import { InkingControl } from "../views/InkingControl";
const requestImageSize = require('../util/request-image-size');
const path = require('path');
@@ -522,6 +523,10 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, viewType: CollectionViewType.Stacking });
}
+ export function MulticolumnDocument(documents: Array<Doc>, options: DocumentOptions) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, viewType: CollectionViewType.Multicolumn });
+ }
+
export function MasonryDocument(documents: Array<Doc>, options: DocumentOptions) {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, viewType: CollectionViewType.Masonry });
}
@@ -660,6 +665,47 @@ export namespace Docs {
throw new Error(`How did ${data} of type ${typeof data} end up in JSON?`);
};
+ export function DocumentFromField(target: Doc, fieldKey: string, proto?: Doc, options?: DocumentOptions): Doc | undefined {
+ let created: Doc | undefined;
+ let layout: ((fieldKey: string) => string) | undefined;
+ const field = target[fieldKey];
+ const resolved = options || {};
+ if (field instanceof ImageField) {
+ created = Docs.Create.ImageDocument((field as ImageField).url.href, resolved);
+ layout = ImageBox.LayoutString;
+ } else if (field instanceof Doc) {
+ created = field;
+ } else if (field instanceof VideoField) {
+ created = Docs.Create.VideoDocument((field as VideoField).url.href, resolved);
+ layout = VideoBox.LayoutString;
+ } else if (field instanceof PdfField) {
+ created = Docs.Create.PdfDocument((field as PdfField).url.href, resolved);
+ layout = PDFBox.LayoutString;
+ } else if (field instanceof IconField) {
+ created = Docs.Create.IconDocument((field as IconField).icon, resolved);
+ layout = IconBox.LayoutString;
+ } else if (field instanceof AudioField) {
+ created = Docs.Create.AudioDocument((field as AudioField).url.href, resolved);
+ layout = AudioBox.LayoutString;
+ } else if (field instanceof HistogramField) {
+ created = Docs.Create.HistogramDocument((field as HistogramField).HistoOp, resolved);
+ layout = HistogramBox.LayoutString;
+ } else if (field instanceof InkField) {
+ const { selectedColor, selectedWidth, selectedTool } = InkingControl.Instance;
+ created = Docs.Create.InkDocument(selectedColor, selectedTool, Number(selectedWidth), (field as InkField).inkData, resolved);
+ layout = InkingStroke.LayoutString;
+ } else if (field instanceof List && field[0] instanceof Doc) {
+ created = Docs.Create.StackingDocument(DocListCast(field), resolved);
+ layout = CollectionView.LayoutString;
+ } else {
+ created = Docs.Create.TextDocument({ ...{ width: 200, height: 25, autoHeight: true }, ...resolved });
+ layout = FormattedTextBox.LayoutString;
+ }
+ created.layout = layout?.(fieldKey);
+ proto && (created.proto = Doc.GetProto(proto));
+ return created;
+ }
+
export async function DocumentFromType(type: string, path: string, options: DocumentOptions): Promise<Opt<Doc>> {
let ctor: ((path: string, options: DocumentOptions) => (Doc | Promise<Doc | undefined>)) | undefined = undefined;
if (type.indexOf("image") !== -1) {
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index da0ad7efe..ff0e19347 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -7,8 +7,7 @@ import { StrCast } from "../../new_fields/Types";
import { Docs } from "../documents/Documents";
import { ScriptField } from "../../new_fields/ScriptField";
-
-function makeTemplate(doc: Doc): boolean {
+export function makeTemplate(doc: Doc, suppressTitle = false): boolean {
const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc;
const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)![0];
const fieldKey = layout.replace("fieldKey={'", "").replace(/'}$/, "");
@@ -17,7 +16,7 @@ function makeTemplate(doc: Doc): boolean {
docs.forEach(d => {
if (!StrCast(d.title).startsWith("-")) {
any = true;
- Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc));
+ Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc), suppressTitle);
} else if (d.type === DocumentType.COL) {
any = makeTemplate(d) || any;
}
@@ -27,7 +26,8 @@ function makeTemplate(doc: Doc): boolean {
export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
data && data.draggedDocuments.map((doc, i) => {
let dbox = doc;
- if (!doc.onDragStart && !doc.onClick && doc.viewType !== CollectionViewType.Linear) {
+ // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
+ if (!doc.onDragStart && !doc.onClick && !doc.isButtonBar) {
const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc;
if (layoutDoc.type === DocumentType.COL) {
layoutDoc.isTemplateDoc = makeTemplate(layoutDoc);
@@ -38,7 +38,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
dbox.dragFactory = layoutDoc;
dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined;
dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)');
- } else if (doc.viewType === CollectionViewType.Linear) {
+ } else if (doc.isButtonBar) {
dbox.ignoreClick = true;
}
data.droppedDocuments[i] = dbox;
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 8f2ec4bef..d953d3bab 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -58,6 +58,9 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
toggleCustom = (e: React.ChangeEvent<HTMLInputElement>): void => {
this.props.docs.map(dv => dv.setCustomView(e.target.checked));
}
+ toggleNarrative = (e: React.ChangeEvent<HTMLInputElement>): void => {
+ this.props.docs.map(dv => dv.setNarrativeView(e.target.checked));
+ }
toggleFloat = (e: React.ChangeEvent<HTMLInputElement>): void => {
SelectionManager.DeselectAll();
@@ -146,6 +149,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
templateMenu.push(<TemplateToggle key={template.Name} template={template} checked={checked} toggle={this.toggleTemplate} />));
templateMenu.push(<OtherToggle key={"float"} name={"Float"} checked={this.props.docs[0].Document.z ? true : false} toggle={this.toggleFloat} />);
templateMenu.push(<OtherToggle key={"custom"} name={"Custom"} checked={StrCast(this.props.docs[0].Document.layoutKey, "layout") !== "layout"} toggle={this.toggleCustom} />);
+ templateMenu.push(<OtherToggle key={"narrative"} name={"Narrative"} checked={StrCast(this.props.docs[0].Document.layoutKey, "layout") === "layout_narrative"} toggle={this.toggleNarrative} />);
templateMenu.push(<OtherToggle key={"chrome"} name={"Chrome"} checked={layout.chromeStatus !== "disabled"} toggle={this.toggleChrome} />);
return (
<Flyout anchorPoint={anchorPoints.LEFT_TOP}
diff --git a/src/client/views/collections/CollectionMulticolumnView.scss b/src/client/views/collections/CollectionMulticolumnView.scss
deleted file mode 100644
index a54af748b..000000000
--- a/src/client/views/collections/CollectionMulticolumnView.scss
+++ /dev/null
@@ -1,23 +0,0 @@
-.collectionMulticolumnView_contents {
- display: flex;
- width: 100%;
- height: 100%;
- overflow: hidden;
-
- .document-wrapper {
- display: flex;
- flex-direction: column;
-
- .display {
- text-align: center;
- height: 20px;
- }
-
- }
-
- .resizer {
- background: black;
- cursor: ew-resize;
- }
-
-} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx
index 6af7cce70..53ad433b3 100644
--- a/src/client/views/collections/CollectionPivotView.tsx
+++ b/src/client/views/collections/CollectionPivotView.tsx
@@ -20,7 +20,7 @@ import { Set } from "typescript-collections";
export class CollectionPivotView extends CollectionSubView(doc => doc) {
componentDidMount = () => {
this.props.Document.freeformLayoutEngine = "pivot";
- if (!this.props.Document.facetCollection) {
+ if (true || !this.props.Document.facetCollection) {
const facetCollection = Docs.Create.FreeformDocument([], { title: "facetFilters", yMargin: 0, treeViewHideTitle: true });
facetCollection.target = this.props.Document;
@@ -34,7 +34,7 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) {
facetCollection.onCheckedClick = new ScriptField(script);
}
- const openDocText = "const alias = getAlias(this); alias.layoutKey = 'layoutCustom'; useRightSplit(alias); ";
+ const openDocText = "const alias = getAlias(this); alias.layoutKey = 'layout_detailed'; useRightSplit(alias); ";
const openDocScript = CompileScript(openDocText, {
params: { this: Doc.name, heading: "boolean", checked: "boolean", context: Doc.name },
typecheck: false,
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 39b4e4e1d..23a664359 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -18,6 +18,9 @@ import { EditableView } from "../EditableView";
import { CollectionStackingView } from "./CollectionStackingView";
import "./CollectionStackingView.scss";
import { TraceMobx } from "../../../new_fields/util";
+import { FormattedTextBox } from "../nodes/FormattedTextBox";
+import { ImageField } from "../../../new_fields/URLField";
+import { ImageBox } from "../nodes/ImageBox";
library.add(faPalette);
@@ -132,6 +135,15 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
@action
addDocument = (value: string, shiftDown?: boolean) => {
+ if (value === ":freeForm") {
+ return this.props.parent.props.addDocument(Docs.Create.FreeformDocument([], { width: 200, height: 200 }));
+ } else if (value.startsWith(":")) {
+ const { Document, addDocument } = this.props.parent.props;
+ const fieldKey = value.substring(1);
+ const proto = Doc.GetProto(Document);
+ const created = Docs.Get.DocumentFromField(Document, fieldKey, proto);
+ return created ? addDocument(created) : false;
+ }
this._createAliasSelected = false;
const key = StrCast(this.props.parent.props.Document.sectionFilter);
const newDoc = Docs.Create.TextDocument({ height: 18, width: 200, documentText: "@@@" + value, title: value, autoHeight: true });
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 70860b6bd..a48208bd9 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -29,6 +29,9 @@ import "./CollectionTreeView.scss";
import React = require("react");
import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
import { ScriptBox } from '../ScriptBox';
+import { ImageBox } from '../nodes/ImageBox';
+import { makeTemplate } from '../../util/DropConverter';
+import { CollectionDockingView } from './CollectionDockingView';
export interface TreeViewProps {
@@ -628,9 +631,35 @@ export class CollectionTreeView extends CollectionSubView(Document) {
layoutItems.push({ description: (this.props.Document.hideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.hideHeaderFields = !this.props.Document.hideHeaderFields, icon: "paint-brush" });
ContextMenu.Instance.addItem({ description: "Treeview Options ...", subitems: layoutItems, icon: "eye" });
}
+ ContextMenu.Instance.addItem({
+ description: "Buxton Layout", icon: "eye", event: () => {
+ const { TextDocument, ImageDocument } = Docs.Create;
+ const wrapper = Docs.Create.StackingDocument([
+ ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { title: "hero" }),
+ TextDocument({ title: "year" }),
+ TextDocument({ title: "degrees_of_freedom" }),
+ TextDocument({ title: "company" }),
+ TextDocument({ title: "short_description" }),
+ ], { autoHeight: true, chromeStatus: "disabled" });
+ wrapper.disableLOD = true;
+ makeTemplate(wrapper, true);
+ const detailedLayout = Doc.MakeAlias(wrapper);
+ const cardLayout = ImageBox.LayoutString("hero");
+ this.childLayoutPairs.forEach(({ layout }) => {
+ const proto = Doc.GetProto(layout);
+ proto.layout = cardLayout;
+ proto.layout_detailed = detailedLayout;
+ layout.showTitle = "title";
+ layout.showTitleHover = "titlehover";
+ });
+ }
+ });
const existingOnClick = ContextMenu.Instance.findByDescription("OnClick...");
const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
- onClicks.push({ description: "Edit onChecked Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Checked Changed ...", this.props.Document, "onCheckedClick", obj.x, obj.y, { heading: "boolean", checked: "boolean" }) });
+ onClicks.push({
+ description: "Edit onChecked Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Checked Changed ...", this.props.Document,
+ "onCheckedClick", obj.x, obj.y, { heading: "boolean", checked: "boolean", context: Doc.name })
+ });
!existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
}
outerXf = () => Utils.GetScreenTransform(this._mainEle!);
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 4bd456233..a665b678b 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,7 +1,7 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import { faEye } from '@fortawesome/free-regular-svg-icons';
import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons';
-import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { action, IReactionDisposer, observable, reaction, runInAction, computed } from 'mobx';
import { observer } from "mobx-react";
import * as React from 'react';
import Lightbox from 'react-image-lightbox-with-rotate';
@@ -10,7 +10,7 @@ import { DateField } from '../../../new_fields/DateField';
import { Doc, DocListCast } from '../../../new_fields/Doc';
import { Id } from '../../../new_fields/FieldSymbols';
import { listSpec } from '../../../new_fields/Schema';
-import { BoolCast, Cast, StrCast } from '../../../new_fields/Types';
+import { BoolCast, Cast, StrCast, NumCast } from '../../../new_fields/Types';
import { ImageField } from '../../../new_fields/URLField';
import { TraceMobx } from '../../../new_fields/util';
import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
@@ -27,7 +27,7 @@ import { CollectionDockingView } from "./CollectionDockingView";
import { AddCustomFreeFormLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
import { CollectionLinearView } from './CollectionLinearView';
-import { CollectionMulticolumnView } from './CollectionMulticolumnView';
+import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
import { CollectionPivotView } from './CollectionPivotView';
import { CollectionSchemaView } from "./CollectionSchemaView";
import { CollectionStackingView } from './CollectionStackingView';
@@ -50,7 +50,8 @@ export enum CollectionViewType {
Pivot,
Linear,
Staff,
- Multicolumn
+ Multicolumn,
+ Timeline
}
export namespace CollectionViewType {
@@ -90,8 +91,18 @@ export class CollectionView extends Touchable<FieldViewProps> {
@observable private static _safeMode = false;
public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; }
+ @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplateField ? Doc.GetProto(this.props.DataDoc) : Doc.GetProto(this.props.Document); }
+ @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); }
+
get collectionViewType(): CollectionViewType | undefined {
- const viewField = Cast(this.props.Document.viewType, "number");
+ if (!this.extensionDoc) return CollectionViewType.Invalid;
+ NumCast(this.props.Document.viewType) && setTimeout(() => {
+ if (this.props.Document.viewType) {
+ this.extensionDoc!.viewType = NumCast(this.props.Document.viewType);
+ }
+ Doc.GetProto(this.props.Document).viewType = this.props.Document.viewType = undefined;
+ });
+ const viewField = NumCast(this.extensionDoc.viewType, Cast(this.props.Document.viewType, "number"));
if (CollectionView._safeMode) {
if (viewField === CollectionViewType.Freeform) {
return CollectionViewType.Tree;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
new file mode 100644
index 000000000..f57ba438a
--- /dev/null
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
@@ -0,0 +1,33 @@
+.collectionMulticolumnView_contents {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+
+ .document-wrapper {
+ display: flex;
+ flex-direction: column;
+
+ .label-wrapper {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ height: 20px;
+ }
+
+ }
+
+ .resizer {
+ cursor: ew-resize;
+ transition: 0.5s opacity ease;
+ display: flex;
+ flex-direction: column;
+
+ .internal {
+ width: 100%;
+ height: 100%;
+ transition: 0.5s background-color ease;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 955e87f13..70e56183c 100644
--- a/src/client/views/collections/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -1,76 +1,93 @@
import { observer } from 'mobx-react';
-import { makeInterface } from '../../../new_fields/Schema';
-import { documentSchema } from '../../../new_fields/documentSchemas';
-import { CollectionSubView } from './CollectionSubView';
+import { makeInterface } from '../../../../new_fields/Schema';
+import { documentSchema } from '../../../../new_fields/documentSchemas';
+import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView';
import * as React from "react";
-import { Doc } from '../../../new_fields/Doc';
-import { NumCast, StrCast, BoolCast } from '../../../new_fields/Types';
-import { ContentFittingDocumentView } from './../nodes/ContentFittingDocumentView';
-import { Utils } from '../../../Utils';
+import { Doc } from '../../../../new_fields/Doc';
+import { NumCast, StrCast, BoolCast } from '../../../../new_fields/Types';
+import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView';
+import { Utils } from '../../../../Utils';
import "./collectionMulticolumnView.scss";
-import { computed, trace } from 'mobx';
-import { Transform } from '../../util/Transform';
+import { computed, trace, observable, action } from 'mobx';
+import { Transform } from '../../../util/Transform';
+import WidthLabel from './MulticolumnWidthLabel';
+import ResizeBar from './MulticolumnResizer';
type MulticolumnDocument = makeInterface<[typeof documentSchema]>;
const MulticolumnDocument = makeInterface(documentSchema);
-interface Unresolved {
- target: Doc;
+interface WidthSpecifier {
magnitude: number;
unit: string;
}
-interface Resolved {
- target: Doc;
- pixels: number;
-}
-
interface LayoutData {
- unresolved: Unresolved[];
- numFixed: number;
- numRatio: number;
+ widthSpecifiers: WidthSpecifier[];
starSum: number;
}
-const resolvedUnits = ["*", "px"];
-const resizerWidth = 2;
-const resizerOpacity = 0.4;
+export const WidthUnit = {
+ Pixel: "px",
+ Ratio: "*"
+};
+
+const resolvedUnits = Object.values(WidthUnit);
+const resizerWidth = 4;
@observer
export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) {
+ /**
+ * @returns the list of layout documents whose width unit is
+ * *, denoting that it will be displayed with a ratio, not fixed pixel, value
+ */
@computed
private get ratioDefinedDocs() {
- return this.childLayoutPairs.map(({ layout }) => layout).filter(({ widthUnit }) => StrCast(widthUnit) === "*");
+ return this.childLayoutPairs.map(({ layout }) => layout).filter(({ widthUnit }) => StrCast(widthUnit) === WidthUnit.Ratio);
}
+ /**
+ * This loops through all childLayoutPairs and extracts the values for widthUnit
+ * and widthMagnitude, ignoring any that are malformed. Additionally, it then
+ * normalizes the ratio values so that one * value is always 1, with the remaining
+ * values proportionate to that easily readable metric.
+ * @returns the list of the resolved width specifiers (unit and magnitude pairs)
+ * as well as the sum of the * coefficients, i.e. the ratio magnitudes
+ */
@computed
private get resolvedLayoutInformation(): LayoutData {
- const unresolved: Unresolved[] = [];
- let starSum = 0, numFixed = 0, numRatio = 0;
-
- for (const { layout } of this.childLayoutPairs) {
- const unit = StrCast(layout.widthUnit);
- const magnitude = NumCast(layout.widthMagnitude);
+ let starSum = 0;
+ const widthSpecifiers: WidthSpecifier[] = [];
+ this.childLayoutPairs.map(({ layout: { widthUnit, widthMagnitude } }) => {
+ const unit = StrCast(widthUnit);
+ const magnitude = NumCast(widthMagnitude);
if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
- if (unit === "*") {
- starSum += magnitude;
- numRatio++;
- } else {
- numFixed++;
- }
- unresolved.push({ target: layout, magnitude, unit });
+ (unit === WidthUnit.Ratio) && (starSum += magnitude);
+ widthSpecifiers.push({ magnitude, unit });
}
- // otherwise, the particular configuration entry is ignored and the remaining
- // space is allocated as if the document were absent from the configuration list
- }
+ /**
+ * Otherwise, the child document is ignored and the remaining
+ * space is allocated as if the document were absent from the child list
+ */
+ });
+ /**
+ * Here, since these values are all relative, adjustments during resizing or
+ * manual updating can, though their ratios remain the same, cause the values
+ * themselves to drift toward zero. Thus, whenever we change any of the values,
+ * we normalize everything (dividing by the smallest magnitude).
+ */
setTimeout(() => {
- const minimum = Math.min(...this.ratioDefinedDocs.map(({ widthMagnitude }) => NumCast(widthMagnitude)));
- this.ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum);
+ const { ratioDefinedDocs } = this;
+ if (this.childLayoutPairs.length) {
+ const minimum = Math.min(...ratioDefinedDocs.map(({ widthMagnitude }) => NumCast(widthMagnitude)));
+ if (minimum !== 0) {
+ ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum);
+ }
+ }
});
- return { unresolved, numRatio, numFixed, starSum };
+ return { widthSpecifiers, starSum };
}
/**
@@ -83,12 +100,12 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
*/
@computed
private get totalFixedAllocation(): number | undefined {
- return this.resolvedLayoutInformation?.unresolved.reduce(
- (sum, { magnitude, unit }) => sum + (unit === "px" ? magnitude : 0), 0);
+ return this.resolvedLayoutInformation?.widthSpecifiers.reduce(
+ (sum, { magnitude, unit }) => sum + (unit === WidthUnit.Pixel ? magnitude : 0), 0);
}
/**
- * This returns the total quantity, in pixels, that this
+ * @returns the total quantity, in pixels, that this
* view needs to reserve for child documents that have
* (with lower priority) requested a certain relative proportion of the
* remaining pixel width not allocated for fixed widths.
@@ -98,14 +115,14 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
*/
@computed
private get totalRatioAllocation(): number | undefined {
- const layoutInfoLen = this.resolvedLayoutInformation?.unresolved.length;
+ const layoutInfoLen = this.resolvedLayoutInformation.widthSpecifiers.length;
if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) {
return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1));
}
}
/**
- * This returns the total quantity, in pixels, that
+ * @returns the total quantity, in pixels, that
* 1* (relative / star unit) is worth. For example,
* if the configuration has three documents, with, respectively,
* widths of 2*, 2* and 1*, and the panel width returns 1000px,
@@ -123,20 +140,37 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
}
}
+ /**
+ * This wrapper function exists to prevent mobx from
+ * needlessly rerendering the internal ContentFittingDocumentViews
+ */
private getColumnUnitLength = () => this.columnUnitLength;
+ /**
+ * @param layout the document whose transform we'd like to compute
+ * Given a layout document, this function
+ * returns the resolved width it has requested, in pixels.
+ * @returns the stored column width if already in pixels,
+ * or the ratio width evaluated to a pixel value
+ */
private lookupPixels = (layout: Doc): number => {
const columnUnitLength = this.columnUnitLength;
if (columnUnitLength === undefined) {
return 0; // we're still waiting on promises to resolve
}
let width = NumCast(layout.widthMagnitude);
- if (StrCast(layout.widthUnit) === "*") {
+ if (StrCast(layout.widthUnit) === WidthUnit.Ratio) {
width *= columnUnitLength;
}
return width;
}
+ /**
+ * @returns the transform that will correctly place
+ * the document decorations box, shifted to the right by
+ * the sum of all the resolved column widths of the
+ * documents before the target.
+ */
private lookupIndividualTransform = (layout: Doc) => {
const columnUnitLength = this.columnUnitLength;
if (columnUnitLength === undefined) {
@@ -145,27 +179,31 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
let offset = 0;
for (const { layout: candidate } of this.childLayoutPairs) {
if (candidate === layout) {
- const shift = offset;
- return this.props.ScreenToLocalTransform().translate(-shift, 0);
+ return this.props.ScreenToLocalTransform().translate(-offset, 0);
}
offset += this.lookupPixels(candidate) + resizerWidth;
}
return Transform.Identity(); // type coersion, this case should never be hit
}
+ /**
+ * @returns the resolved list of rendered child documents, displayed
+ * at their resolved pixel widths, each separated by a resizer.
+ */
@computed
private get contents(): JSX.Element[] | null {
- trace();
const { childLayoutPairs } = this;
const { Document, PanelHeight } = this.props;
const collector: JSX.Element[] = [];
for (let i = 0; i < childLayoutPairs.length; i++) {
const { layout } = childLayoutPairs[i];
collector.push(
- <div className={"document-wrapper"}>
+ <div
+ className={"document-wrapper"}
+ key={Utils.GenerateGuid()}
+ >
<ContentFittingDocumentView
{...this.props}
- key={Utils.GenerateGuid()}
Document={layout}
DataDocument={layout.resolvedDataDoc as Doc}
PanelWidth={() => this.lookupPixels(layout)}
@@ -201,98 +239,4 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
);
}
-}
-
-interface SpacerProps {
- width: number;
- columnUnitLength(): number | undefined;
- toLeft?: Doc;
- toRight?: Doc;
-}
-
-interface WidthLabelProps {
- layout: Doc;
- collectionDoc: Doc;
- decimals?: number;
-}
-
-@observer
-class WidthLabel extends React.Component<WidthLabelProps> {
-
- @computed
- private get contents() {
- const { layout, decimals } = this.props;
- const magnitude = NumCast(layout.widthMagnitude).toFixed(decimals ?? 3);
- const unit = StrCast(layout.widthUnit);
- return <span className={"display"}>{magnitude} {unit}</span>;
- }
-
- render() {
- return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null);
- }
-
-}
-
-@observer
-class ResizeBar extends React.Component<SpacerProps> {
-
- private registerResizing = (e: React.PointerEvent<HTMLDivElement>) => {
- e.stopPropagation();
- e.preventDefault();
- window.removeEventListener("pointermove", this.onPointerMove);
- window.removeEventListener("pointerup", this.onPointerUp);
- window.addEventListener("pointermove", this.onPointerMove);
- window.addEventListener("pointerup", this.onPointerUp);
- }
-
- private onPointerMove = ({ movementX }: PointerEvent) => {
- const { toLeft, toRight, columnUnitLength } = this.props;
- const target = movementX > 0 ? toRight : toLeft;
- let scale = columnUnitLength();
- if (target && scale) {
- const { widthUnit, widthMagnitude } = target;
- scale = widthUnit === "*" ? scale : 1;
- target.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / scale;
- }
- }
-
- private get isActivated() {
- const { toLeft, toRight } = this.props;
- if (toLeft && toRight) {
- if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") {
- return false;
- }
- return true;
- } else if (toLeft) {
- if (StrCast(toLeft.widthUnit) === "px") {
- return false;
- }
- return true;
- } else if (toRight) {
- if (StrCast(toRight.widthUnit) === "px") {
- return false;
- }
- return true;
- }
- return false;
- }
-
- private onPointerUp = () => {
- window.removeEventListener("pointermove", this.onPointerMove);
- window.removeEventListener("pointerup", this.onPointerUp);
- }
-
- render() {
- return (
- <div
- className={"resizer"}
- style={{
- width: this.props.width,
- opacity: this.isActivated ? resizerOpacity : 0
- }}
- onPointerDown={this.registerResizing}
- />
- );
- }
-
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
new file mode 100644
index 000000000..11e210958
--- /dev/null
+++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
@@ -0,0 +1,116 @@
+import * as React from "react";
+import { observer } from "mobx-react";
+import { observable, action } from "mobx";
+import { Doc } from "../../../../new_fields/Doc";
+import { NumCast, StrCast } from "../../../../new_fields/Types";
+import { WidthUnit } from "./CollectionMulticolumnView";
+
+interface ResizerProps {
+ width: number;
+ columnUnitLength(): number | undefined;
+ toLeft?: Doc;
+ toRight?: Doc;
+}
+
+enum ResizeMode {
+ Global = "blue",
+ Pinned = "red",
+ Undefined = "black"
+}
+
+const resizerOpacity = 1;
+
+@observer
+export default class ResizeBar extends React.Component<ResizerProps> {
+ @observable private isHoverActive = false;
+ @observable private isResizingActive = false;
+ @observable private resizeMode = ResizeMode.Undefined;
+
+ @action
+ private registerResizing = (e: React.PointerEvent<HTMLDivElement>, mode: ResizeMode) => {
+ e.stopPropagation();
+ e.preventDefault();
+ this.resizeMode = mode;
+ window.removeEventListener("pointermove", this.onPointerMove);
+ window.removeEventListener("pointerup", this.onPointerUp);
+ window.addEventListener("pointermove", this.onPointerMove);
+ window.addEventListener("pointerup", this.onPointerUp);
+ this.isResizingActive = true;
+ }
+
+ private onPointerMove = ({ movementX }: PointerEvent) => {
+ const { toLeft, toRight, columnUnitLength } = this.props;
+ const movingRight = movementX > 0;
+ const toNarrow = movingRight ? toRight : toLeft;
+ const toWiden = movingRight ? toLeft : toRight;
+ const unitLength = columnUnitLength();
+ if (unitLength) {
+ if (toNarrow) {
+ const { widthUnit, widthMagnitude } = toNarrow;
+ const scale = widthUnit === WidthUnit.Ratio ? unitLength : 1;
+ toNarrow.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / scale;
+ }
+ if (this.resizeMode === ResizeMode.Pinned && toWiden) {
+ const { widthUnit, widthMagnitude } = toWiden;
+ const scale = widthUnit === WidthUnit.Ratio ? unitLength : 1;
+ toWiden.widthMagnitude = NumCast(widthMagnitude) + Math.abs(movementX) / scale;
+ }
+ }
+ }
+
+ private get isActivated() {
+ const { toLeft, toRight } = this.props;
+ if (toLeft && toRight) {
+ if (StrCast(toLeft.widthUnit) === WidthUnit.Pixel && StrCast(toRight.widthUnit) === WidthUnit.Pixel) {
+ return false;
+ }
+ return true;
+ } else if (toLeft) {
+ if (StrCast(toLeft.widthUnit) === WidthUnit.Pixel) {
+ return false;
+ }
+ return true;
+ } else if (toRight) {
+ if (StrCast(toRight.widthUnit) === WidthUnit.Pixel) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @action
+ private onPointerUp = () => {
+ this.resizeMode = ResizeMode.Undefined;
+ this.isResizingActive = false;
+ this.isHoverActive = false;
+ window.removeEventListener("pointermove", this.onPointerMove);
+ window.removeEventListener("pointerup", this.onPointerUp);
+ }
+
+ render() {
+ return (
+ <div
+ className={"resizer"}
+ style={{
+ width: this.props.width,
+ opacity: this.isActivated && this.isHoverActive ? resizerOpacity : 0
+ }}
+ onPointerEnter={action(() => this.isHoverActive = true)}
+ onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}
+ >
+ <div
+ className={"internal"}
+ onPointerDown={e => this.registerResizing(e, ResizeMode.Pinned)}
+ style={{ backgroundColor: this.resizeMode }}
+ />
+ <div
+ className={"internal"}
+ onPointerDown={e => this.registerResizing(e, ResizeMode.Global)}
+ style={{ backgroundColor: this.resizeMode }}
+ />
+ </div>
+ );
+ }
+
+} \ No newline at end of file
diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx
new file mode 100644
index 000000000..b394fed62
--- /dev/null
+++ b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx
@@ -0,0 +1,56 @@
+import * as React from "react";
+import { observer } from "mobx-react";
+import { computed } from "mobx";
+import { Doc } from "../../../../new_fields/Doc";
+import { NumCast, StrCast, BoolCast } from "../../../../new_fields/Types";
+import { EditableView } from "../../EditableView";
+import { WidthUnit } from "./CollectionMulticolumnView";
+
+interface WidthLabelProps {
+ layout: Doc;
+ collectionDoc: Doc;
+ decimals?: number;
+}
+
+@observer
+export default class WidthLabel extends React.Component<WidthLabelProps> {
+
+ @computed
+ private get contents() {
+ const { layout, decimals } = this.props;
+ const getUnit = () => StrCast(layout.widthUnit);
+ const getMagnitude = () => String(+NumCast(layout.widthMagnitude).toFixed(decimals ?? 3));
+ return (
+ <div className={"label-wrapper"}>
+ <EditableView
+ GetValue={getMagnitude}
+ SetValue={value => {
+ const converted = Number(value);
+ if (!isNaN(converted) && converted > 0) {
+ layout.widthMagnitude = converted;
+ return true;
+ }
+ return false;
+ }}
+ contents={getMagnitude()}
+ />
+ <EditableView
+ GetValue={getUnit}
+ SetValue={value => {
+ if (Object.values(WidthUnit).includes(value)) {
+ layout.widthUnit = value;
+ return true;
+ }
+ return false;
+ }}
+ contents={getUnit()}
+ />
+ </div>
+ );
+ }
+
+ render() {
+ return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null);
+ }
+
+} \ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a833afe4e..c35a44860 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -48,6 +48,7 @@ import { GestureUtils } from '../../../pen-gestures/GestureUtils';
import { RadialMenu } from './RadialMenu';
import { RadialMenuProps } from './RadialMenuItem';
+import { CollectionStackingView } from '../collections/CollectionStackingView';
library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
@@ -644,6 +645,20 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@undoBatch
@action
+ setNarrativeView = (custom: boolean): void => {
+ if (custom) {
+ this.props.Document.layout_narrative = CollectionView.LayoutString("narrative");
+ this.props.Document.nativeWidth = this.props.Document.nativeHeight = undefined;
+ !this.props.Document.narrative && (Doc.GetProto(this.props.Document).narrative = new List<Doc>([]));
+ this.props.Document.viewType = CollectionViewType.Stacking;
+ this.props.Document.layoutKey = "layout_narrative";
+ } else {
+ DocumentView.makeNativeViewClicked(this.props.Document);
+ }
+ }
+
+ @undoBatch
+ @action
setCustomView = (custom: boolean): void => {
if (this.props.ContainingCollectionView?.props.DataDoc || this.props.ContainingCollectionView?.props.Document.isTemplateDoc) {
Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.Document);
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index c56fde186..6e6ee1712 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -54,7 +54,7 @@ export interface FieldViewProps {
@observer
export class FieldView extends React.Component<FieldViewProps> {
public static LayoutString(fieldType: { name: string }, fieldStr: string) {
- return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "<ImageBox {...props} fieldKey={"dada} />"
+ return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "<ImageBox {...props} fieldKey={"data} />"
}
@computed
diff --git a/src/scraping/buxton/node_scraper.ts b/src/scraping/buxton/node_scraper.ts
new file mode 100644
index 000000000..ef1d989d4
--- /dev/null
+++ b/src/scraping/buxton/node_scraper.ts
@@ -0,0 +1,57 @@
+import { readdirSync } from "fs";
+import { resolve } from "path";
+
+const StreamZip = require('node-stream-zip');
+
+export async function open(path: string) {
+ const zip = new StreamZip({
+ file: path,
+ storeEntries: true
+ });
+ return new Promise<string>((resolve, reject) => {
+ zip.on('ready', () => {
+ console.log("READY!", zip.entriesCount);
+ for (const entry of Object.values(zip.entries()) as any[]) {
+ const desc = entry.isDirectory ? 'directory' : `${entry.size} bytes`;
+ console.log(`Entry ${entry.name}: ${desc}`);
+ }
+ let body = "";
+ zip.stream("word/document.xml", (error: any, stream: any) => {
+ if (error) {
+ reject(error);
+ }
+ stream.on('data', (chunk: any) => body += chunk.toString());
+ stream.on('end', () => {
+ resolve(body);
+ zip.close();
+ });
+ });
+ });
+ });
+}
+
+export async function extract(path: string) {
+ const contents = await open(path);
+ let body = "";
+ const components = contents.toString().split('<w:t');
+ for (const component of components) {
+ const tags = component.split('>');
+ console.log(tags[1]);
+ const content = tags[1].replace(/<.*$/, "");
+ body += content;
+ }
+ return body;
+}
+
+async function parse(): Promise<string[]> {
+ const sourceDirectory = resolve(`${__dirname}/source`);
+ const candidates = readdirSync(sourceDirectory).filter(file => file.endsWith(".doc") || file.endsWith(".docx")).map(file => `${sourceDirectory}/${file}`);
+ await extract(candidates[0]);
+ try {
+ return Promise.all(candidates.map(extract));
+ } catch {
+ return [];
+ }
+}
+
+parse(); \ No newline at end of file
diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py
index a9256073b..2d1a5ca32 100644
--- a/src/scraping/buxton/scraper.py
+++ b/src/scraping/buxton/scraper.py
@@ -13,11 +13,12 @@ import math
import sys
source = "./source"
-dist = "../../server/public/files"
+filesPath = "../../server/public/files"
+image_dist = filesPath + "/images/buxton"
db = MongoClient("localhost", 27017)["Dash"]
target_collection = db.newDocuments
-target_doc_title = "Workspace 1"
+target_doc_title = "Collection 1"
schema_guids = []
common_proto_id = ""
@@ -70,7 +71,7 @@ def text_doc_map(string_list):
return listify(proxify_guids(list(map(guid_map, string_list))))
-def write_collection(parse_results, display_fields, storage_key, viewType=2):
+def write_collection(parse_results, display_fields, storage_key, viewType):
view_guids = parse_results["child_guids"]
data_doc = parse_results["schema"]
@@ -99,13 +100,18 @@ def write_collection(parse_results, display_fields, storage_key, viewType=2):
fields[storage_key] = listify(proxify_guids(view_guids))
fields["schemaColumns"] = listify(display_fields)
fields["backgroundColor"] = "white"
- fields["scale"] = 0.5
fields["viewType"] = 2
fields["author"] = "Bill Buxton"
+ fields["disableLOD"] = True
fields["creationDate"] = {
"date": datetime.datetime.utcnow().microsecond,
"__type": "date"
}
+ if "image_urls" in parse_results:
+ fields["hero"] = {
+ "url": parse_results["image_urls"][0],
+ "__type": "image"
+ }
fields["isPrototype"] = True
fields["page"] = -1
@@ -167,14 +173,17 @@ def write_text_doc(content):
def write_image(folder, name):
- path = f"http://localhost:1050/files/{folder}/{name}"
+ path = f"http://localhost:1050/files/images/buxton/{folder}/{name}"
data_doc_guid = guid()
view_doc_guid = guid()
- image = Image.open(f"{dist}/{folder}/{name}")
+ image = Image.open(f"{image_dist}/{folder}/{name}")
native_width, native_height = image.size
+ if abs(native_width - native_height) < 10:
+ return None
+
view_doc = {
"_id": view_doc_guid,
"fields": {
@@ -213,7 +222,10 @@ def write_image(folder, name):
target_collection.insert_one(view_doc)
target_collection.insert_one(data_doc)
- return view_doc_guid
+ return {
+ "layout_id": view_doc_guid,
+ "url": path
+ }
def parse_document(file_name: str):
@@ -222,20 +234,26 @@ def parse_document(file_name: str):
result = {}
- dir_path = dist + "/" + pure_name
+ dir_path = image_dist + "/" + pure_name
+ print(dir_path)
mkdir_if_absent(dir_path)
raw = str(docx2txt.process(source + "/" + file_name, dir_path))
+ urls = []
view_guids = []
count = 0
for image in os.listdir(dir_path):
- count += 1
- view_guids.append(write_image(pure_name, image))
- copyfile(dir_path + "/" + image, dir_path +
- "/" + image.replace(".", "_o.", 1))
- copyfile(dir_path + "/" + image, dir_path +
- "/" + image.replace(".", "_m.", 1))
+ created = write_image(pure_name, image)
+ if created != None:
+ urls.append(created["url"])
+ view_guids.append(created["layout_id"])
+ count += 1
+ resolved = dir_path + "/" + image
+ original = dir_path + "/" + image.replace(".", "_o.", 1)
+ medium = dir_path + "/" + image.replace(".", "_m.", 1)
+ copyfile(resolved, original)
+ copyfile(resolved, medium)
print(f"extracted {count} images...")
def sanitize(line): return re.sub("[\n\t]+", "", line).replace(u"\u00A0", " ").replace(
@@ -342,7 +360,8 @@ def parse_document(file_name: str):
"fields": result,
"__type": "Doc"
},
- "child_guids": view_guids
+ "child_guids": view_guids,
+ "image_urls": urls
}
@@ -356,21 +375,19 @@ def write_common_proto():
"_id": id,
"fields": {
"proto": protofy("collectionProto"),
- "title": "Common Import Proto",
+ "title": "The Buxton Collection",
},
"__type": "Doc"
}
-
target_collection.insert_one(common_proto)
-
return id
-if os.path.exists(dist):
- shutil.rmtree(dist)
-while os.path.exists(dist):
+if os.path.exists(image_dist):
+ shutil.rmtree(image_dist)
+while os.path.exists(image_dist):
pass
-os.mkdir(dist)
+os.mkdir(image_dist)
mkdir_if_absent(source)
common_proto_id = write_common_proto()
@@ -380,7 +397,7 @@ for file_name in os.listdir(source):
if file_name.endswith('.docx'):
candidates += 1
schema_guids.append(write_collection(
- parse_document(file_name), ["title", "data"], "image_data"))
+ parse_document(file_name), ["title", "data"], "data", 5))
print("writing parent schema...")
parent_guid = write_collection({
@@ -390,7 +407,7 @@ parent_guid = write_collection({
"__type": "Doc"
},
"child_guids": schema_guids
-}, ["title", "short_description", "original_price"], "data", 1)
+}, ["title", "short_description", "original_price"], "data", 4)
print("appending parent schema to main workspace...\n")
target_collection.update_one(
@@ -400,7 +417,7 @@ target_collection.update_one(
print("rewriting .gitignore...\n")
lines = ['*', '!.gitignore']
-with open(dist + "/.gitignore", 'w') as f:
+with open(filesPath + "/.gitignore", 'w') as f:
f.write('\n'.join(lines))
suffix = "" if candidates == 1 else "s"
diff --git a/src/scraping/buxton/source/Bill_Notes_NB75D.docx b/src/scraping/buxton/source/Bill_Notes_NB75D.docx
new file mode 100644
index 000000000..a5a5e3d90
--- /dev/null
+++ b/src/scraping/buxton/source/Bill_Notes_NB75D.docx
Binary files differ