diff options
-rw-r--r-- | package-lock.json | 84 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 32 | ||||
-rw-r--r-- | src/client/views/collections/CollectionViewChromes.tsx | 39 | ||||
-rw-r--r-- | src/client/views/collections/collectionGrid/CollectionGridView.scss | 6 | ||||
-rw-r--r-- | src/client/views/collections/collectionGrid/CollectionGridView.tsx | 407 | ||||
-rw-r--r-- | src/client/views/collections/collectionGrid/Grid.tsx | 2 |
6 files changed, 207 insertions, 363 deletions
diff --git a/package-lock.json b/package-lock.json index e692b266d..457104c8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2841,8 +2841,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -2860,13 +2859,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2879,18 +2876,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -2993,8 +2987,7 @@ }, "inherits": { "version": "2.0.4", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -3004,7 +2997,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3017,20 +3009,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.5", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.9.0", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3047,7 +3036,6 @@ "mkdirp": { "version": "0.5.3", "bundled": true, - "optional": true, "requires": { "minimist": "^1.2.5" } @@ -3103,8 +3091,7 @@ }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "npm-packlist": { "version": "1.4.8", @@ -3129,8 +3116,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -3140,7 +3126,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3209,8 +3194,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -3240,7 +3224,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3258,7 +3241,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3297,13 +3279,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.1.1", - "bundled": true, - "optional": true + "bundled": true } } } @@ -9535,7 +9515,7 @@ }, "chownr": { "version": "1.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "ci-info": { @@ -9841,7 +9821,7 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, "defaults": { @@ -10340,7 +10320,7 @@ }, "glob": { "version": "7.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", @@ -10428,7 +10408,7 @@ }, "hosted-git-info": { "version": "2.8.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" }, "http-cache-semantics": { @@ -10564,7 +10544,7 @@ }, "is-ci": { "version": "1.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "requires": { "ci-info": "^1.5.0" @@ -10640,7 +10620,7 @@ }, "is-retry-allowed": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" }, "is-stream": { @@ -11149,7 +11129,7 @@ }, "mkdirp": { "version": "0.5.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", "requires": { "minimist": "^1.2.5" @@ -11157,7 +11137,7 @@ "dependencies": { "minimist": { "version": "1.2.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } @@ -11209,7 +11189,7 @@ }, "node-gyp": { "version": "5.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz", "integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==", "requires": { "env-paths": "^2.2.0", @@ -11323,7 +11303,7 @@ }, "npm-packlist": { "version": "1.4.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", "requires": { "ignore-walk": "^3.0.1", @@ -11343,7 +11323,7 @@ }, "npm-profile": { "version": "4.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz", "integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==", "requires": { "aproba": "^1.1.2 || 2", @@ -11353,7 +11333,7 @@ }, "npm-registry-fetch": { "version": "4.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz", "integrity": "sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw==", "requires": { "JSONStream": "^1.3.4", @@ -11788,7 +11768,7 @@ }, "rc": { "version": "1.2.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "requires": { "deep-extend": "^0.6.0", @@ -11799,7 +11779,7 @@ "dependencies": { "minimist": { "version": "1.2.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } @@ -11858,7 +11838,7 @@ }, "readable-stream": { "version": "3.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", @@ -11879,7 +11859,7 @@ }, "registry-auth-token": { "version": "3.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", "requires": { "rc": "^1.1.6", @@ -11943,7 +11923,7 @@ }, "rimraf": { "version": "2.7.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" @@ -12242,7 +12222,7 @@ }, "string_decoder": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "requires": { "safe-buffer": "~5.2.0" @@ -12250,7 +12230,7 @@ "dependencies": { "safe-buffer": { "version": "5.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" } } @@ -12562,7 +12542,7 @@ }, "widest-line": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", "requires": { "string-width": "^2.1.1" diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 524997d20..215b5bce8 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -244,38 +244,6 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - const existingVm = ContextMenu.Instance.findByDescription("View Modes..."); - const subItems = existingVm && "subitems" in existingVm ? existingVm.subitems : []; - subItems.push({ description: "Freeform", event: () => { this.props.Document._viewType = CollectionViewType.Freeform; }, icon: "signature" }); - if (CollectionView._safeMode) { - ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => this.props.Document._viewType = CollectionViewType.Invalid, icon: "project-diagram" }); - } - subItems.push({ description: "Schema", event: () => this.props.Document._viewType = CollectionViewType.Schema, icon: "th-list" }); - subItems.push({ description: "Treeview", event: () => this.props.Document._viewType = CollectionViewType.Tree, icon: "tree" }); - subItems.push({ description: "Stacking", event: () => this.props.Document._viewType = CollectionViewType.Stacking, icon: "ellipsis-v" }); - subItems.push({ - description: "Stacking (AutoHeight)", event: () => { - this.props.Document._viewType = CollectionViewType.Stacking; - this.props.Document._autoHeight = true; - }, icon: "ellipsis-v" - }); - subItems.push({ description: "Staff", event: () => this.props.Document._viewType = CollectionViewType.Staff, icon: "music" }); - subItems.push({ description: "Multicolumn", event: () => this.props.Document._viewType = CollectionViewType.Multicolumn, icon: "columns" }); - subItems.push({ description: "Multirow", event: () => this.props.Document._viewType = CollectionViewType.Multirow, icon: "columns" }); - subItems.push({ description: "Masonry", event: () => this.props.Document._viewType = CollectionViewType.Masonry, icon: "columns" }); - subItems.push({ description: "Carousel", event: () => this.props.Document._viewType = CollectionViewType.Carousel, icon: "columns" }); - subItems.push({ description: "Pivot/Time", event: () => this.props.Document._viewType = CollectionViewType.Time, icon: "columns" }); - subItems.push({ description: "Map", event: () => this.props.Document._viewType = CollectionViewType.Map, icon: "globe-americas" }); - subItems.push({ description: "Grid", event: () => this.props.Document._viewType = CollectionViewType.Grid, icon: "th-list" }); - switch (this.props.Document._viewType) { - case CollectionViewType.Freeform: { - subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); - break; - } - } - subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" }); - !existingVm && ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems, icon: "eye" }); - this.setupViewTypes("Add a Perspective...", vtype => { const newRendition = Doc.MakeAlias(this.props.Document); newRendition._viewType = vtype; diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 63080d2e6..53bff0fe5 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -16,6 +16,7 @@ import { CollectionViewType } from "./CollectionView"; import { CollectionView } from "./CollectionView"; import "./CollectionViewChromes.scss"; import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; +import { undo } from "prosemirror-history"; const datepicker = require('js-datepicker'); interface CollectionViewChromeProps { @@ -589,14 +590,16 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro this.resizeListenerDisposer?.(); } + get numCols() { return NumCast(this.props.CollectionView.props.Document.gridNumCols, 10); } + /** * Sets the value of `numCols` on the grid's Document to the value entered. */ @undoBatch onNumColsEnter = (e: React.KeyboardEvent<HTMLInputElement>) => { if (e.key === "Enter" || e.key === "Tab") { - if (e.currentTarget.valueAsNumber > 0 && this.props.CollectionView.props.Document.numCols as number !== e.currentTarget.valueAsNumber) { - this.props.CollectionView.props.Document.numCols = e.currentTarget.valueAsNumber; + if (e.currentTarget.valueAsNumber > 0) { + this.props.CollectionView.props.Document.gridNumCols = e.currentTarget.valueAsNumber; } } @@ -617,8 +620,9 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro /** * Sets whether the grid is flexible or not on the grid's Document. */ + @undoBatch toggleFlex = () => { - this.props.CollectionView.props.Document.flexGrid = !this.props.CollectionView.props.Document.flexGrid; + this.props.CollectionView.props.Document.gridFlex = !this.props.CollectionView.props.Document.gridFlex; } /** @@ -626,8 +630,8 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro */ onIncrementButtonClick = () => { this.clicked = true; - this.entered && (this.props.CollectionView.props.Document.numCols as number)--; - undoBatch(() => (this.props.CollectionView.props.Document.numCols as number)++)(); + this.entered && (this.props.CollectionView.props.Document.gridNumCols as number)--; + undoBatch(() => this.props.CollectionView.props.Document.gridNumCols = this.numCols + 1)(); this.entered = false; } @@ -637,8 +641,8 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro onDecrementButtonClick = () => { this.clicked = true; if (!this.decrementLimitReached) { - this.entered && (this.props.CollectionView.props.Document.numCols as number)++; - undoBatch(() => (this.props.CollectionView.props.Document.numCols as number)--)(); + this.entered && (this.props.CollectionView.props.Document.gridNumCols as number)++; + undoBatch(() => this.props.CollectionView.props.Document.gridNumCols = this.numCols - 1)(); } this.entered = false; } @@ -649,7 +653,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro incrementValue = () => { this.entered = true; if (!this.clicked && !this.decrementLimitReached) { - (this.props.CollectionView.props.Document.numCols as number)++; + this.props.CollectionView.props.Document.gridNumCols = this.numCols + 1; } this.decrementLimitReached = false; this.clicked = false; @@ -661,8 +665,8 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro decrementValue = () => { this.entered = true; if (!this.clicked) { - if (this.props.CollectionView.props.Document.numCols as number !== 1) { - (this.props.CollectionView.props.Document.numCols as number)--; + if (this.numCols !== 1) { + this.props.CollectionView.props.Document.gridNumCols = this.numCols - 1; } else { this.decrementLimitReached = true; @@ -676,14 +680,15 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro * Toggles the value of preventCollision */ toggleCollisions = () => { - this.props.CollectionView.props.Document.preventCollision = !this.props.CollectionView.props.Document.preventCollision; + this.props.CollectionView.props.Document.gridPreventCollision = !this.props.CollectionView.props.Document.gridPreventCollision; } /** * Changes the value of the compactType */ + @undoBatch changeCompactType = (e: React.ChangeEvent<HTMLSelectElement>) => { - this.props.CollectionView.props.Document.compactType = e.target.selectedOptions[0].value; + this.props.CollectionView.props.Document.gridCompaction = e.target.selectedOptions[0].value; } render() { @@ -693,7 +698,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro <span className="grid-icon"> <FontAwesomeIcon icon="columns" size="1x" /> </span> - <input className="collectionGridViewChrome-entryBox" type="number" placeholder={this.props.CollectionView.props.Document.numCols as string} onKeyDown={this.onNumColsEnter} onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} /> + <input className="collectionGridViewChrome-entryBox" type="number" placeholder={this.numCols.toString()} onKeyDown={this.onNumColsEnter} onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} /> <input className="columnButton" onClick={this.onIncrementButtonClick} onMouseEnter={this.incrementValue} onMouseLeave={this.decrementValue} type="button" value="↑" /> <input className="columnButton" style={{ marginRight: 5 }} onClick={this.onDecrementButtonClick} onMouseEnter={this.decrementValue} onMouseLeave={this.incrementValue} type="button" value="↓" /> </span> @@ -704,7 +709,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro <input className="collectionGridViewChrome-entryBox" type="number" placeholder={this.props.CollectionView.props.Document.rowHeight as string} onKeyDown={this.onRowHeightEnter} onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { e.stopPropagation(); e.preventDefault(); e.currentTarget.focus(); }} /> </span> */} <span className="grid-control" style={{ width: this.resize ? "12%" : "20%" }}> - <input type="checkbox" style={{ marginRight: 5 }} onClick={this.toggleCollisions} defaultChecked={!this.props.CollectionView.props.Document.preventCollision} /> + <input type="checkbox" style={{ marginRight: 5 }} onClick={this.toggleCollisions} defaultChecked={!this.props.CollectionView.props.Document.gridPreventCollision} /> <label className="flexLabel">{this.resize ? "Coll" : "Collisions"}</label> </span> @@ -712,7 +717,7 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro style={{ marginRight: 5 }} onPointerDown={stopPropagation} onChange={this.changeCompactType} - value={StrCast(this.props.CollectionView.props.Document.compactType)}> + value={StrCast(this.props.CollectionView.props.Document.gridCompaction)}> > {["vertical", "horizontal", "null"].map(type => <option className="collectionGridViewChrome-viewOption" @@ -724,11 +729,11 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewChro </select> <span className="grid-control" style={{ width: this.resize ? "12%" : "20%" }}> - <input style={{ marginRight: 5 }} type="checkbox" onClick={this.toggleFlex} defaultChecked={this.props.CollectionView.props.Document.flexGrid as boolean} /> + <input style={{ marginRight: 5 }} type="checkbox" onClick={this.toggleFlex} defaultChecked={BoolCast(this.props.CollectionView.props.Document.gridFlex)} /> <label className="flexLabel">{this.resize ? "Flex" : "Flexible"}</label> </span> - <button onClick={() => this.props.CollectionView.props.Document.resetLayout = true}> + <button onClick={() => this.props.CollectionView.props.Document.gridResetLayout = true}> {!this.resize ? "Reset" : <FontAwesomeIcon icon="redo-alt" size="1x" />} </button> diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.scss b/src/client/views/collections/collectionGrid/CollectionGridView.scss index de7d62475..9c2d5cbff 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.scss +++ b/src/client/views/collections/collectionGrid/CollectionGridView.scss @@ -21,6 +21,10 @@ max-width: 100%; } + .react-grid-layout { + width : 100%; + } + .react-grid-item>.react-resizable-handle { z-index: 4; // doesn't work on prezi otherwise } @@ -41,7 +45,7 @@ position: absolute; height: 3; left: 5; - top: 40; + top: 30; transform-origin: left; transform: rotate(90deg); outline: none; diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index a820b7e0e..2e1f7a0db 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -1,85 +1,61 @@ -import { computed, observable, Lambda, action, reaction } from 'mobx'; +import { action, computed, Lambda, observable, reaction } from 'mobx'; +import { observer } from 'mobx-react'; import * as React from "react"; import { Doc, Opt } from '../../../../fields/Doc'; import { documentSchema } from '../../../../fields/documentSchemas'; +import { Id } from '../../../../fields/FieldSymbols'; import { makeInterface } from '../../../../fields/Schema'; -import { BoolCast, NumCast, StrCast, ScriptCast } from '../../../../fields/Types'; +import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; +import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils'; +import { Docs } from '../../../documents/Documents'; +import { DragManager } from '../../../util/DragManager'; +import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; +import { ContextMenu } from '../../ContextMenu'; +import { ContextMenuProps } from '../../ContextMenuItem'; import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView'; +import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { CollectionSubView } from '../CollectionSubView'; -import { SubCollectionViewProps } from '../CollectionSubView'; -import { returnZero } from '../../../../Utils'; -import Grid, { Layout } from "./Grid"; -import { Id } from '../../../../fields/FieldSymbols'; -import { observer } from 'mobx-react'; -import { SnappingManager } from '../../../util/SnappingManager'; -import { Docs } from '../../../documents/Documents'; -import { EditableView, EditableProps } from '../../EditableView'; import "./CollectionGridView.scss"; -import { ContextMenu } from '../../ContextMenu'; -import { List } from '../../../../fields/List'; -import { ContextMenuProps } from '../../ContextMenuItem'; - +import Grid, { Layout } from "./Grid"; type GridSchema = makeInterface<[typeof documentSchema]>; const GridSchema = makeInterface(documentSchema); @observer export class CollectionGridView extends CollectionSubView(GridSchema) { - private containerRef: React.RefObject<HTMLDivElement>; + private _containerRef: React.RefObject<HTMLDivElement> = React.createRef(); + private _changeListenerDisposer: Opt<Lambda>; // listens for changes in this.childLayoutPairs + private _resetListenerDisposer: Opt<Lambda>; // listens for when the reset button is clicked + @observable private _rowHeight: Opt<number>; // temporary store of row height to make change undoable @observable private _scroll: number = 0; // required to make sure the decorations box container updates on scroll - private changeListenerDisposer: Opt<Lambda>; // listens for changes in this.childLayoutPairs - private rowHeight: number = 0; // temporary store of row height to make change undoable - private mounted: boolean = false; // hack to fix the issue of not rerendering when mounting - private resetListenerDisposer: Opt<Lambda>; // listens for when the reset button is clicked - - constructor(props: Readonly<SubCollectionViewProps>) { - super(props); - - this.props.Document.numCols = NumCast(this.props.Document.numCols, 10); - this.props.Document.rowHeight = NumCast(this.props.Document.rowHeight, 100); - - // determines whether the grid is static/flexible i.e. whether can nodes be moved around and resized or not - this.props.Document.flexGrid = BoolCast(this.props.Document.flexGrid, true); - // determines whether nodes should remain in position, be bound to the top, or to the left - this.props.Document.compactType = StrCast(this.props.Document.compactType, "vertical"); - - // determines whether nodes should move out of the way (i.e. collide) when other nodes are dragged over them - this.props.Document.preventCollision = BoolCast(this.props.Document.preventCollision, false); + @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } - // sets the default width and height of the grid nodes - this.props.Document.defaultW = NumCast(this.props.Document.defaultW, 2); - this.props.Document.defaultH = NumCast(this.props.Document.defaultH, 2); + @computed get numCols() { return NumCast(this.props.Document.gridNumCols, 10); } + @computed get rowHeight() { return this._rowHeight === undefined ? NumCast(this.props.Document.gridRowHeight, 100) : this._rowHeight; } + // sets the default width and height of the grid nodes + @computed get defaultW() { return NumCast(this.props.Document.gridDefaultW, 2); } + @computed get defaultH() { return NumCast(this.props.Document.gridDefaultH, 2); } - // sets the margin between grid nodes - this.props.Document.margin = NumCast(this.props.Document.margin, 10); + @computed get colWidthPlusGap() { return (this.props.PanelWidth() - this.margin) / this.numCols; } + @computed get rowHeightPlusGap() { return this.rowHeight + this.margin; } - // sets the css display type of the ContentFittingDocumentView component - this.props.Document.display = StrCast(this.props.Document.display, "contents"); + @computed get margin() { return NumCast(this.props.Document.margin, 10); } // sets the margin between grid nodes - this.setLayout = this.setLayout.bind(this); - this.onSliderChange = this.onSliderChange.bind(this); - this.onContextMenu = this.onContextMenu.bind(this); - - this.containerRef = React.createRef(); - } + @computed get flexGrid() { return BoolCast(this.props.Document.gridFlex, true); } // is grid static/flexible i.e. whether nodes be moved around and resized componentDidMount() { - this.mounted = true; - - this.changeListenerDisposer = computed(() => this.childLayoutPairs).observe(({ oldValue, newValue }) => { - - const layouts: Layout[] = this.parsedLayoutList; + this._changeListenerDisposer = computed(() => this.childLayoutPairs).observe(({ oldValue, newValue }) => { + const layouts = this.parsedLayoutList; // if grid view has been opened and then exited and a document has been deleted // this deletes the layout of that document from the layouts list if (!oldValue && newValue.length) { layouts.forEach(({ i }, index) => { - const targetId = i; - if (!newValue.find(({ layout: preserved }) => preserved[Id] === targetId)) { + if (!newValue.find(({ layout: preserved }) => preserved[Id] === i)) { layouts.splice(index, 1); } }); @@ -88,120 +64,84 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { if (!oldValue || newValue.length > oldValue.length) { // for each document that was added, add a corresponding grid layout object newValue.forEach(({ layout }, i) => { - const targetId = layout[Id]; - if (!layouts.find((gridLayout: Layout) => gridLayout.i === targetId)) { - layouts.push({ - i: targetId, - w: this.defaultW, - h: this.defaultH, - x: this.defaultW * (i % Math.floor(NumCast(this.props.Document.numCols) / this.defaultW)), - y: this.defaultH * Math.floor(i / Math.floor(NumCast(this.props.Document.numCols) / this.defaultH)), - static: !this.props.Document.flexGrid - }); + if (!layouts.find(gridLayout => gridLayout.i === layout[Id])) { + this.addLayoutItem(layouts, this.makeLayoutItem(layout, this.unflexedPosition(i), !this.flexGrid)) } - }); + }) } else { // for each document that was removed, remove its corresponding grid layout object oldValue.forEach(({ layout }) => { - const targetId = layout[Id]; - if (!newValue.find(({ layout: preserved }) => preserved[Id] === targetId)) { - const index = layouts.findIndex((gridLayout: Layout) => gridLayout.i === targetId); + if (!newValue.find(({ layout: preserved }) => preserved[Id] === layout[Id])) { + const index = layouts.findIndex((gridLayout: Layout) => gridLayout.i === layout[Id]); index !== -1 && layouts.splice(index, 1); } }); } - this.unStringifiedLayoutList = layouts; + this.setLayoutList(layouts); }, true); // updates the layouts if the reset button has been clicked - this.resetListenerDisposer = reaction(() => this.props.Document.resetLayout, () => { - if (this.props.Document.flexGrid) { - const layouts: Layout[] = this.parsedLayoutList; - this.setLayout( - layouts.map(({ i }, index) => ({ - i: i, - x: this.defaultW * (index % Math.floor(NumCast(this.props.Document.numCols) / this.defaultW)), - y: this.defaultH * Math.floor(index / Math.floor(NumCast(this.props.Document.numCols) / this.defaultH)), - w: this.defaultW, - h: this.defaultH, - }))); + this._resetListenerDisposer = reaction(() => this.props.Document.gridResetLayout, (reset) => { + if (reset && this.flexGrid) { + this.setLayout(this.childLayoutPairs.map((pair, index) => this.makeLayoutItem(pair.layout, this.unflexedPosition(index)))); } - this.props.Document.resetLayout = false; + this.props.Document.gridResetLayout = false; }); } componentWillUnmount() { - this.mounted = false; - this.changeListenerDisposer && this.changeListenerDisposer(); - this.resetListenerDisposer?.(); + this._changeListenerDisposer?.(); + this._resetListenerDisposer?.(); } - /** - * @returns the transform that will correctly place the document decorations box. - */ - private lookupIndividualTransform = (layout: Layout) => { - const index = this.childLayoutPairs.findIndex(({ layout: layoutDoc }) => layoutDoc[Id] === layout.i); - - // translations depend on whether the grid is flexible or static - const xTranslation = (this.props.Document.flexGrid ? NumCast(layout.x) : this.defaultW * (index % Math.floor(NumCast(this.props.Document.numCols) / this.defaultW))) * this.colWidthPlusGap + this.margin; - const yTranslation = (this.props.Document.flexGrid ? NumCast(layout.y) : this.defaultH * Math.floor(index / Math.floor(NumCast(this.props.Document.numCols) / this.defaultH))) * this.rowHeightPlusGap + this.margin - this._scroll + 30; // 30 is the height of the add text doc bar - - return this.props.ScreenToLocalTransform().translate(-xTranslation, -yTranslation); + unflexedPosition(index: number) { + return { + x: (index % Math.floor(this.numCols / this.defaultW)) * this.defaultW, + y: Math.floor(index / Math.floor(this.numCols / this.defaultH)) * this.defaultH + }; } - @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } + screenToCell(sx: number, sy: number) { + const pt = this.props.ScreenToLocalTransform().transformPoint(sx, sy); + const x = Math.floor(pt[0] / this.colWidthPlusGap); + const y = Math.floor((pt[1] + this._scroll) / this.rowHeight); + return { x, y }; + } - addDocTab = (doc: Doc, where: string) => { - if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { - this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]); - return true; - } - return this.props.addDocTab(doc, where); + makeLayoutItem = (doc: Doc, pos: { x: number, y: number }, Static: boolean = false, w: number = this.defaultW, h: number = this.defaultH) => { + return ({ i: doc[Id], w, h, x: pos.x, y: pos.y, static: Static }); } - @computed get colWidthPlusGap() { return (this.props.PanelWidth() - this.margin) / NumCast(this.props.Document.numCols); } - @computed get rowHeightPlusGap() { return NumCast(this.props.Document.rowHeight) + this.margin; } + addLayoutItem = (layouts: Layout[], layout: Layout) => { + const f = layouts.findIndex(l => l.i === layout.i); + f !== -1 && layouts.splice(f, 1); + layouts.push(layout); + return layouts; + } + /** + * @returns the transform that will correctly place the document decorations box. + */ + private lookupIndividualTransform = (layout: Layout) => { + const xypos = this.flexGrid ? layout : this.unflexedPosition(this.layoutList.findIndex(l => l.i === layout.i)); + const pos = { x: xypos.x * this.colWidthPlusGap + this.margin, y: xypos.y * this.rowHeightPlusGap + this.margin - this._scroll }; - @computed get margin() { return NumCast(this.props.Document.margin); } - @computed get defaultW() { return NumCast(this.props.Document.defaultW); } - @computed get defaultH() { return NumCast(this.props.Document.defaultH); } + return this.props.ScreenToLocalTransform().translate(-pos.x, -pos.y); + } /** * @returns the layout list converted from JSON */ get parsedLayoutList() { - return this.props.Document.gridLayoutString ? JSON.parse(StrCast(this.props.Document.gridLayoutString)) : []; + return (this.props.Document.gridLayoutString ? JSON.parse(StrCast(this.props.Document.gridLayoutString)) : []) as Layout[]; } /** * Stores the layout list on the Document as JSON */ - set unStringifiedLayoutList(layouts: Layout[]) { - - // sometimes there are issues with rendering when you switch from a different view - // where the nodes are all squeezed together on the left hand side of the screen - // until you click on the screen or close the chrome or interact with it in some way - // the component doesn't rerender when the component mounts - // this seems to fix that though it isn't very elegant - - this.mounted && (this.props.Document.gridLayoutString = ""); + setLayoutList(layouts: Layout[]) { this.props.Document.gridLayoutString = JSON.stringify(layouts); - this.mounted = false; } - - /** - * Sets the width of the decorating box. - * @param layout - */ - @observable private width = (layout: Layout) => (this.props.Document.flexGrid ? layout.w : this.defaultW) * this.colWidthPlusGap - this.margin; - - /** - * Sets the height of the decorating box. - * @param layout - */ - @observable private height = (layout: Layout) => (this.props.Document.flexGrid ? layout.h : this.defaultH) * this.rowHeightPlusGap - this.margin; - /** * * @param layout @@ -217,7 +157,6 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { DataDoc={layout.resolvedDataDoc as Doc} NativeHeight={returnZero} NativeWidth={returnZero} - addDocTab={this.addDocTab} backgroundColor={this.props.backgroundColor} ContainingCollectionDoc={this.props.Document} PanelWidth={width} @@ -226,7 +165,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { onClick={this.onChildClickHandler} renderDepth={this.props.renderDepth + 1} parentActive={this.props.active} - display={StrCast(this.props.Document.display)} + display={StrCast(this.props.Document.display, "contents")} // sets the css display type of the ContentFittingDocumentView component />; } @@ -234,27 +173,18 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { * Saves the layouts received from the Grid to the Document. * @param layouts `Layout[]` */ - @undoBatch @action - setLayout(layoutArray: Layout[]) { + setLayout = (layoutArray: Layout[]) => { // for every child in the collection, check to see if there's a corresponding grid layout object and // updated layout object. If both exist, which they should, update the grid layout object from the updated object - - if (this.props.Document.flexGrid) { - const layouts: Layout[] = this.parsedLayoutList; + if (this.flexGrid) { + const layouts = this.parsedLayoutList; this.childLayoutPairs.forEach(({ layout: doc }) => { - let update: Opt<Layout>; - const targetId = doc[Id]; - const gridLayout = layouts.find(gridLayout => gridLayout.i === targetId); - if (gridLayout && (update = layoutArray.find(layout => layout.i === targetId))) { - gridLayout.x = update.x; - gridLayout.y = update.y; - gridLayout.w = update.w; - gridLayout.h = update.h; - } + let gridLayout = layouts.find(gridLayout => gridLayout.i === doc[Id]); + gridLayout && Object.assign(gridLayout, layoutArray.find(layout => layout.i === doc[Id]) || gridLayout); }); - this.unStringifiedLayoutList = layouts; + this.setLayoutList(layouts); } } @@ -264,27 +194,22 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { */ @computed private get contents(): JSX.Element[] { - - const { childLayoutPairs } = this; const collector: JSX.Element[] = []; - const layouts: Layout[] = this.parsedLayoutList; - if (!layouts.length || layouts.length !== childLayoutPairs.length) { - return []; - } - - for (let i = 0; i < childLayoutPairs.length; i++) { - const { layout } = childLayoutPairs[i]; - const gridLayout = layouts[i]; - const dxf = () => this.lookupIndividualTransform(gridLayout); - const width = () => this.width(gridLayout); - const height = () => this.height(gridLayout); - collector.push( - <div className={this.props.Document.flexGrid && (this.props.isSelected() ? true : false) ? "document-wrapper" : "document-wrapper static"} - key={gridLayout.i} - > - {this.getDisplayDoc(layout, dxf, width, height)} - </div > - ); + const layouts = this.parsedLayoutList; + if (layouts.length !== this.childLayoutPairs.length) { + setTimeout(action(() => this.props.Document.gridResetLayout = true), 0); + } else { + this.layoutList.forEach((l, i) => { + const child = this.childLayoutPairs.find(c => c.layout[Id] === l.i); + const dxf = () => this.lookupIndividualTransform(layouts[i]); + const width = () => (this.flexGrid ? layouts[i].w : this.defaultW) * this.colWidthPlusGap - this.margin; + const height = () => (this.flexGrid ? layouts[i].h : this.defaultH) * this.rowHeightPlusGap - this.margin; + child && collector.push( + <div key={child.layout[Id]} className={"document-wrapper" + (this.flexGrid && this.props.isSelected() ? "" : " static")} > + {this.getDisplayDoc(child.layout, dxf, width, height)} + </div > + ); + }); } return collector; } @@ -293,56 +218,42 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { * @returns a list of `Layout` objects with attributes depending on whether the grid is flexible or static */ get layoutList(): Layout[] { - - const layouts: Layout[] = this.parsedLayoutList; - - return this.props.Document.flexGrid ? - layouts.map(({ i, x, y, w, h }) => ({ - i: i, - x: x + w > NumCast(this.props.Document.numCols) ? 0 : x, // handles wrapping around of nodes when numCols decreases - y: y, - w: w > NumCast(this.props.Document.numCols) ? NumCast(this.props.Document.numCols) : w, // reduces width if greater than numCols - h: h, + return this.flexGrid ? + this.parsedLayoutList.map(({ i, x, y, w, h }) => ({ + i, y, h, + x: x + w > this.numCols ? 0 : x, // handles wrapping around of nodes when numCols decreases + w: Math.max(w, this.numCols), // reduces width if greater than numCols static: BoolCast(this.childLayoutPairs.find(({ layout }) => layout[Id] === i)?.layout.lockedPosition, false) // checks if the lock position item has been selected in the context menu - })) - : layouts.map(({ i }, index) => ({ - i: i, - x: this.defaultW * (index % Math.floor(NumCast(this.props.Document.numCols) / this.defaultW)), - y: this.defaultH * Math.floor(index / Math.floor(NumCast(this.props.Document.numCols) / this.defaultH)), - w: this.defaultW, - h: this.defaultH, - static: true - })); + })) : + this.parsedLayoutList.map((layout, index) => Object.assign(layout, this.unflexedPosition(index))); } - /** - * Handles the change in the value of the rowHeight slider. - */ - onSliderChange = (event: React.ChangeEvent<HTMLInputElement>) => { - this.props.Document.rowHeight = event.currentTarget.valueAsNumber; + onInternalDrop = (e: Event, de: DragManager.DropEvent) => { + const layouts = this.parsedLayoutList; + const dropped = de.complete.docDragData?.droppedDocuments; + if (dropped && super.onInternalDrop(e, de) && layouts.length !== this.childDocs.length) { + dropped.forEach(doc => this.addLayoutItem(layouts, this.makeLayoutItem(doc, this.screenToCell(de.x, de.y)))); // shouldn't place all docs in the same cell; + this.setLayoutList(layouts); + return true; + } + return false; } /** - * Saves the rowHeight in a temporary variable to make it undoable later. + * Handles the change in the value of the rowHeight slider. */ - onSliderDown = () => { - this.rowHeight = NumCast(this.props.Document.rowHeight); + @action + onSliderChange = (event: React.ChangeEvent<HTMLInputElement>) => { + this._rowHeight = event.currentTarget.valueAsNumber; } - - /** - * Uses the stored rowHeight to make the rowHeight change undoable. - */ - onSliderUp = () => { - const tempVal = this.props.Document.rowHeight; - this.props.Document.rowHeight = this.rowHeight; - undoBatch(() => this.props.Document.rowHeight = tempVal)(); + @action + onSliderDown = (e: React.PointerEvent) => { + this._rowHeight = this.rowHeight; // uses _rowHeight during dragging and sets doc's rowHeight when finished so that operation is undoable + setupMoveUpEvents(this, e, returnFalse, action(() => { + undoBatch(() => this.props.Document.gridRowHeight = this._rowHeight)(); + this._rowHeight = undefined; + }), emptyFunction, false, false); } - - /** - * Creates a text document and adds it to the grid. - */ - @undoBatch @action addTextDocument = (value: string) => this.props.addDocument(Docs.Create.TextDocument(value, { title: value })); - /** * Adds the display option to change the css display attribute of the `ContentFittingDocumentView`s */ @@ -350,74 +261,52 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { const displayOptionsMenu: ContextMenuProps[] = []; displayOptionsMenu.push({ description: "Contents", event: () => this.props.Document.display = "contents", icon: "copy" }); displayOptionsMenu.push({ description: "Undefined", event: () => this.props.Document.display = undefined, icon: "exclamation" }); - ContextMenu.Instance.addItem({ description: "Display", subitems: displayOptionsMenu, icon: "tv" }); } - render() { - - // for the add text document EditableView - const newEditableViewProps: EditableProps = { - GetValue: () => "", - SetValue: this.addTextDocument, - contents: "+ ADD TEXT DOCUMENT", - }; - - const childDocumentViews: JSX.Element[] = this.contents; - const chromeStatus = this.props.Document._chromeStatus; - const showChrome = (chromeStatus !== 'view-mode' && chromeStatus !== 'disabled'); + onPointerDown = (e: React.PointerEvent) => { + this.props.isSelected(true) && setupMoveUpEvents(this, e, returnFalse, returnFalse, action((e: PointerEvent, doubleTap?: boolean) => { + if (doubleTap) { + const text = Docs.Create.TextDocument("", { _width: 150, _height: 50 }); + FormattedTextBox.SelectOnLoad = text[Id];// 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.Document, this.props.fieldKey, text); + this.setLayoutList(this.addLayoutItem(this.parsedLayoutList, this.makeLayoutItem(text, this.screenToCell(e.clientX, e.clientY)))); + } + }), false); + e.stopPropagation(); + } + render() { return ( - <div className="collectionGridView-contents" - style={{ - pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined - }} + <div className="collectionGridView-contents" ref={this.createDashEventsTarget} + style={{ pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined }} onContextMenu={this.onContextMenu} - ref={this.createDashEventsTarget} - onPointerDown={e => { - if (this.props.active(true)) { - if (this.props.isSelected(true)) { - e.stopPropagation(); - } - } - // is the following section needed? it prevents the slider from being easily used and I'm not sure what it's preventing - - // if (this.props.isSelected(true)) { - // !((e.target as any)?.className.includes("react-resizable-handle")) && e.preventDefault(); - // } - - }} // the grid doesn't stopPropagation when its widgets are hit, so we need to otherwise the outer documents will respond - > - {showChrome ? - <div className="collectionGridView-addDocumentButton"> - <EditableView {...newEditableViewProps} /> - </div> : null - } - <div className="collectionGridView-gridContainer" - ref={this.containerRef} + onPointerDown={e => this.onPointerDown(e)} > + <div className="collectionGridView-gridContainer" ref={this._containerRef} + onWheel={e => e.stopPropagation()} onScroll={action(e => { if (!this.props.isSelected()) e.currentTarget.scrollTop = this._scroll; else this._scroll = e.currentTarget.scrollTop; - })} - onWheel={e => e.stopPropagation()} - > - <input className="rowHeightSlider" type="range" value={NumCast(this.props.Document.rowHeight)} onPointerDown={this.onSliderDown} onPointerUp={this.onSliderUp} onChange={this.onSliderChange} style={{ width: this.props.PanelHeight() - 40 }} min={1} max={this.props.PanelHeight() - 40} /> + })} > + <input className="rowHeightSlider" type="range" + style={{ width: this.props.PanelHeight() - 30 }} + min={1} value={this.rowHeight} max={this.props.PanelHeight() - 30} + onPointerDown={this.onSliderDown} onChange={this.onSliderChange} /> <Grid width={this.props.PanelWidth()} - nodeList={childDocumentViews.length ? childDocumentViews : null} - layout={childDocumentViews.length ? this.layoutList : undefined} + nodeList={this.contents.length ? this.contents : null} + layout={this.contents.length ? this.layoutList : undefined} childrenDraggable={this.props.isSelected() ? true : false} - numCols={NumCast(this.props.Document.numCols)} - rowHeight={NumCast(this.props.Document.rowHeight)} + numCols={this.numCols} + rowHeight={this.rowHeight} setLayout={this.setLayout} transformScale={this.props.ScreenToLocalTransform().Scale} - compactType={StrCast(this.props.Document.compactType)} - preventCollision={BoolCast(this.props.Document.preventCollision)} + compactType={StrCast(this.props.Document.gridCompaction, "vertical")} // determines whether nodes should remain in position, be bound to the top, or to the left + preventCollision={BoolCast(this.props.Document.gridPreventCollision)}// determines whether nodes should move out of the way (i.e. collide) when other nodes are dragged over them margin={this.margin} /> - </div> </div > ); } -} +}
\ No newline at end of file diff --git a/src/client/views/collections/collectionGrid/Grid.tsx b/src/client/views/collections/collectionGrid/Grid.tsx index 6232fca7c..66edb99d9 100644 --- a/src/client/views/collections/collectionGrid/Grid.tsx +++ b/src/client/views/collections/collectionGrid/Grid.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { observer } from "mobx-react"; - import "../../../../../node_modules/react-grid-layout/css/styles.css"; import "../../../../../node_modules/react-resizable/css/styles.css"; @@ -29,7 +28,6 @@ interface GridProps { */ @observer export default class Grid extends React.Component<GridProps> { - render() { const compactType = this.props.compactType === "vertical" || this.props.compactType === "horizontal" ? this.props.compactType : null; return ( |